diff options
Diffstat (limited to 'src/tools')
28 files changed, 1590 insertions, 1367 deletions
diff --git a/src/tools/aueffectutil.mm b/src/tools/aueffectutil.mm index 661800a3b48..b8a83de4c64 100644 --- a/src/tools/aueffectutil.mm +++ b/src/tools/aueffectutil.mm @@ -16,29 +16,12 @@ #include <cstdlib> -#ifdef MAC_OS_X_VERSION_MAX_ALLOWED - -#if MAC_OS_X_VERSION_MAX_ALLOWED < 1060 - -typedef ComponentDescription AudioComponentDescription; - -@protocol NSApplicationDelegate <NSObject> -@end - -@protocol NSWindowDelegate <NSObject> -@end - -#endif // MAC_OS_X_VERSION_MAX_ALLOWED < 1060 - -#endif // MAC_OS_X_VERSION_MAX_ALLOWED - - struct EffectInfo { - Component component; - OSType type; - OSType subtype; - OSType manufacturer; + AudioComponent component; + OSType type; + OSType subtype; + OSType manufacturer; }; @@ -173,7 +156,7 @@ static void UpdateChangeCountCallback( if (!customViewValid) { forceGenericView = YES; - [genericViewButton setState:NSOnState]; + [genericViewButton setState:NSControlStateValueOn]; } CFIndex const presetCount = (NULL != presets) ? CFArrayGetCount(presets) : 0; @@ -256,11 +239,11 @@ static void UpdateChangeCountCallback( - (void)makeWindowControllers { genericViewButton = [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 100, 18)]; [genericViewButton setAutoresizingMask:NSViewNotSizable]; - [[genericViewButton cell] setControlSize:NSSmallControlSize]; - [genericViewButton setButtonType:NSSwitchButton]; + [[genericViewButton cell] setControlSize:NSControlSizeSmall]; + [genericViewButton setButtonType:NSButtonTypeSwitch]; [genericViewButton setBordered:NO]; [genericViewButton setAllowsMixedState:NO]; - [genericViewButton setState:(forceGenericView ? NSOnState : NSOffState)]; + [genericViewButton setState:(forceGenericView ? NSControlStateValueOn : NSControlStateValueOff)]; [genericViewButton setTitle:@"Use generic editor view"]; [genericViewButton setAction:@selector(toggleGenericView:)]; [genericViewButton setTarget:self]; @@ -268,8 +251,8 @@ static void UpdateChangeCountCallback( presetButton = [[NSPopUpButton alloc] initWithFrame:NSMakeRect(0, 0, 100, 22) pullsDown:YES]; [presetButton setAutoresizingMask:NSViewNotSizable]; - [[presetButton cell] setControlSize:NSSmallControlSize]; - [[presetButton cell] setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]]; + [[presetButton cell] setControlSize:NSControlSizeSmall]; + [[presetButton cell] setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSControlSizeSmall]]]; [presetButton setTitle:@"Load preset"]; [[[presetButton menu] addItemWithTitle:@"Load preset" action:NULL keyEquivalent:@""] setHidden:YES]; [presetButton sizeToFit]; @@ -297,9 +280,9 @@ static void UpdateChangeCountCallback( [presetButton release]; window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, headerSize.width, headerSize.height) - styleMask:(NSTitledWindowMask | - NSClosableWindowMask | - NSMiniaturizableWindowMask) + styleMask:(NSWindowStyleMaskTitled | + NSWindowStyleMaskClosable | + NSWindowStyleMaskMiniaturizable) backing:NSBackingStoreBuffered defer:YES]; [window setReleasedWhenClosed:NO]; @@ -346,22 +329,20 @@ static void UpdateChangeCountCallback( return NO; } - NSString *errDesc = nil; - id const desc = [NSPropertyListSerialization propertyListFromData:data - mutabilityOption:0 + NSError *errDesc = nil; + id const desc = [NSPropertyListSerialization propertyListWithData:data + options:NSPropertyListImmutable format:NULL - errorDescription:&errDesc]; + error:&errDesc]; if (!desc || ![desc isKindOfClass:[NSDictionary class]] || errDesc) { if (error) { - NSString *const message = [NSString stringWithFormat:@"Error in file format (%@)", errDesc]; + NSString *const message = [NSString stringWithFormat:@"Error in file format (%@)", [errDesc localizedDescription]]; NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message, NSLocalizedDescriptionKey, nil]; *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info]; } - if (errDesc) - [errDesc release]; return NO; } @@ -579,7 +560,7 @@ static void UpdateChangeCountCallback( && [[desc objectForKey:ForceGenericViewKey] respondsToSelector:@selector(boolValue)]) { forceGenericView = [[desc objectForKey:ForceGenericViewKey] boolValue]; - [genericViewButton setState:(forceGenericView ? NSOnState : NSOffState)]; + [genericViewButton setState:(forceGenericView ? NSControlStateValueOn : NSControlStateValueOff)]; } if ([desc objectForKey:WindowFrameKey] && [[desc objectForKey:WindowFrameKey] isKindOfClass:[NSString class]]) @@ -647,32 +628,31 @@ static void UpdateChangeCountCallback( return nil; } - NSString *errDesc = nil; - NSData *const data = [NSPropertyListSerialization dataFromPropertyList:desc + NSError *errDesc = nil; + NSData *const data = [NSPropertyListSerialization dataWithPropertyList:desc format:NSPropertyListXMLFormat_v1_0 - errorDescription:&errDesc]; + options:0 + error:&errDesc]; if (!data || errDesc) { if (error) { NSString *message; if (errDesc) - message = [NSString stringWithFormat:@"Error serialising effect settings: %@", errDesc]; + message = [NSString stringWithFormat:@"Error serialising effect settings: %@", [errDesc localizedDescription]]; else message = @"Error serialising effect settings"; NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message, NSLocalizedDescriptionKey, nil]; *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info]; } - if (errDesc) - [errDesc release]; return nil; } return data; } - (IBAction)toggleGenericView:(id)sender { - forceGenericView = (NSOnState == [sender state]); + forceGenericView = (NSControlStateValueOn == [sender state]); if (view) { [[NSNotificationCenter defaultCenter] removeObserver:self @@ -697,7 +677,7 @@ static void UpdateChangeCountCallback( [alert setInformativeText:[NSString stringWithFormat:@"Tried to select preset %ld of %ld", (long)idx + 1, (long)total]]; - [alert beginSheetModalForWindow:window modalDelegate:nil didEndSelector:NULL contextInfo:NULL]; + [alert beginSheetModalForWindow:window completionHandler:nil]; return; } @@ -715,7 +695,7 @@ static void UpdateChangeCountCallback( [alert setMessageText:[NSString stringWithFormat:@"Error loading preset %@", preset->presetName]]; [alert setInformativeText:[NSString stringWithFormat:@"Error %ld encountered while setting AudioUnit property", (long)status]]; - [alert beginSheetModalForWindow:window modalDelegate:nil didEndSelector:NULL contextInfo:NULL]; + [alert beginSheetModalForWindow:window completionHandler:nil]; return; } @@ -728,7 +708,7 @@ static void UpdateChangeCountCallback( preset->presetName]]; [alert setInformativeText:[NSString stringWithFormat:@"Error %ld encountered while sending notification", (long)status]]; - [alert beginSheetModalForWindow:window modalDelegate:nil didEndSelector:NULL contextInfo:NULL]; + [alert beginSheetModalForWindow:window completionHandler:nil]; return; } } @@ -793,7 +773,7 @@ static void UpdateChangeCountCallback( item = [menu addItemWithTitle:[NSString stringWithFormat:@"Hide %@", appName] action:@selector(hide:) keyEquivalent:@"h"]; item = [menu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; - [item setKeyEquivalentModifierMask:NSCommandKeyMask | NSAlternateKeyMask]; + [item setKeyEquivalentModifierMask:NSEventModifierFlagCommand | NSEventModifierFlagOption]; item = [menu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; [menu addItem:[NSMenuItem separatorItem]]; @@ -895,7 +875,7 @@ static void UpdateChangeCountCallback( if ((0 > index) || (0 == effects[index].component)) { NSAlert *const alert = [[NSAlert alloc] init]; - [alert setAlertStyle:NSWarningAlertStyle]; + [alert setAlertStyle:NSAlertStyleWarning]; [alert setMessageText:@"Invalid effect component"]; [alert addButtonWithTitle:@"OK"]; [alert runModal]; @@ -910,17 +890,18 @@ static void UpdateChangeCountCallback( subtypeValue, ComponentSubTypeKey, manufacturerValue, ComponentManufacturerKey, nil]; - NSString *errDesc = nil; - NSData *const data = [NSPropertyListSerialization dataFromPropertyList:desc + NSError *errDesc = nil; + NSData *const data = [NSPropertyListSerialization dataWithPropertyList:desc format:NSPropertyListXMLFormat_v1_0 - errorDescription:&errDesc]; + options:0 + error:&errDesc]; if (!data || errDesc) { NSAlert *const alert = [[NSAlert alloc] init]; - [alert setAlertStyle:NSWarningAlertStyle]; + [alert setAlertStyle:NSAlertStyleWarning]; [alert setMessageText:@"Error serialising properties for new effect"]; if (errDesc) - [alert setInformativeText:[errDesc autorelease]]; + [alert setInformativeText:[errDesc localizedDescription]]; [alert addButtonWithTitle:@"OK"]; [alert runModal]; [alert release]; @@ -939,7 +920,7 @@ static void UpdateChangeCountCallback( else { NSAlert *const alert = [[NSAlert alloc] init]; - [alert setAlertStyle:NSWarningAlertStyle]; + [alert setAlertStyle:NSAlertStyleWarning]; [alert setMessageText:@"Error creating new effect document"]; [alert addButtonWithTitle:@"OK"]; [alert runModal]; @@ -978,38 +959,35 @@ static void UpdateChangeCountCallback( } - (void)applicationDidFinishLaunching:(NSNotification *)notification { - ComponentDescription effectFilter = { kAudioUnitType_Effect, 0, 0, 0, 0 }; - long const count = CountComponents(&effectFilter); + AudioComponentDescription effectFilter = { kAudioUnitType_Effect, 0, 0, 0, 0 }; + long const count = AudioComponentCount(&effectFilter); if (0 == count) { NSAlert *const alert = [[NSAlert alloc] init]; - [alert setAlertStyle:NSWarningAlertStyle]; + [alert setAlertStyle:NSAlertStyleWarning]; [alert setMessageText:@"No AudioUnit effects found"]; [alert addButtonWithTitle:@"OK"]; [alert runModal]; [alert release]; } - std::vector<std::pair<Component, OSStatus> > failed; + std::vector<std::pair<AudioComponent, OSStatus> > failed; effects = (EffectInfo *)malloc(count * sizeof(*effects)); - Component effect = FindNextComponent(0, &effectFilter); - for (long i = 0; (i < count) && (effect != 0); i++, effect = FindNextComponent(effect, &effectFilter)) + AudioComponent effect = AudioComponentFindNext(nullptr, &effectFilter); + for (long i = 0; (i < count) && effect; i++, effect = AudioComponentFindNext(effect, &effectFilter)) { - ComponentDescription effectDesc; - Handle const nameHandle = NewHandle(4); - OSStatus const err = GetComponentInfo(effect, &effectDesc, nameHandle, NULL, NULL); + OSStatus err; + AudioComponentDescription effectDesc; + CFStringRef name = nullptr; + err = AudioComponentGetDescription(effect, &effectDesc); + if (noErr == err) + err = AudioComponentCopyName(effect, &name); if (noErr == err) { effects[i].component = effect; effects[i].type = effectDesc.componentType; effects[i].subtype = effectDesc.componentSubType; effects[i].manufacturer = effectDesc.componentManufacturer; - HLock(nameHandle); - CFStringRef const name = CFStringCreateWithPascalString( - NULL, - (unsigned char const *)*nameHandle, - kCFStringEncodingMacRoman); - HUnlock(nameHandle); NSMenuItem *const item = [newEffectMenu addItemWithTitle:(NSString *)name action:@selector(newEffect:) keyEquivalent:@""]; @@ -1020,9 +998,8 @@ static void UpdateChangeCountCallback( else { effects[i].component = 0; - failed.push_back(std::make_pair(effect, err)); + failed.emplace_back(effect, err); } - DisposeHandle(nameHandle); } if (!failed.empty()) @@ -1031,7 +1008,7 @@ static void UpdateChangeCountCallback( (unsigned long)failed.size(), ((1U == failed.size()) ? "" : "s")]; NSMutableString *const detail = [NSMutableString stringWithCapacity:(16 * failed.size())]; - std::vector<std::pair<Component, OSStatus> >::const_iterator it = failed.begin(); + std::vector<std::pair<AudioComponent, OSStatus> >::const_iterator it = failed.begin(); [detail appendFormat:@"%lu (%ld)", (unsigned long)it->first, (long)it->second]; ++it; while (failed.end() != it) @@ -1040,7 +1017,7 @@ static void UpdateChangeCountCallback( ++it; } NSAlert *const alert = [[NSAlert alloc] init]; - [alert setAlertStyle:NSWarningAlertStyle]; + [alert setAlertStyle:NSAlertStyleWarning]; [alert setMessageText:message]; [alert setInformativeText:[NSString stringWithString:detail]]; [alert addButtonWithTitle:@"OK"]; diff --git a/src/tools/chdman.cpp b/src/tools/chdman.cpp index 3a4277c50d1..353ac88ce6b 100644 --- a/src/tools/chdman.cpp +++ b/src/tools/chdman.cpp @@ -17,13 +17,14 @@ #include "hashing.h" #include "md5.h" #include "multibyte.h" +#include "osdcore.h" #include "path.h" #include "strformat.h" #include "vbiparse.h" +#include <array> #include <cassert> #include <cctype> -#include <cstdarg> #include <cstdio> #include <cstdlib> #include <cstring> @@ -32,7 +33,13 @@ #include <limits> #include <memory> #include <new> +#include <optional> +#include <regex> +#include <string_view> +#include <tuple> #include <unordered_map> +#include <utility> +#include <vector> using util::string_format; @@ -50,16 +57,23 @@ using util::string_format; #define I64FMT "ll" #endif +// hunk size limits +constexpr uint32_t HUNK_SIZE_MIN = 16; +constexpr uint32_t HUNK_SIZE_MAX = 1024 * 1024; + // default hard disk sector size -const uint32_t IDE_SECTOR_SIZE = 512; +constexpr uint32_t IDE_SECTOR_SIZE = 512; // temporary input buffer size -const uint32_t TEMP_BUFFER_SIZE = 32 * 1024 * 1024; +constexpr uint32_t TEMP_BUFFER_SIZE = 32 * 1024 * 1024; // modes -const int MODE_NORMAL = 0; -const int MODE_CUEBIN = 1; -const int MODE_GDI = 2; +constexpr int MODE_NORMAL = 0; +constexpr int MODE_CUEBIN = 1; +constexpr int MODE_GDI = 2; + +// osd printf verbosity +constexpr bool OSD_PRINTF_VERBOSE = false; // command modifier #define REQUIRED "~" @@ -88,6 +102,7 @@ const int MODE_GDI = 2; #define OPTION_INPUT "input" #define OPTION_OUTPUT "output" #define OPTION_OUTPUT_BIN "outputbin" +#define OPTION_OUTPUT_SPLITBIN "splitbin" #define OPTION_OUTPUT_FORCE "force" #define OPTION_INPUT_START_BYTE "inputstartbyte" #define OPTION_INPUT_START_HUNK "inputstarthunk" @@ -121,7 +136,9 @@ const int MODE_GDI = 2; typedef std::unordered_map<std::string, std::string *> parameters_map; -template <typename Format, typename... Params> [[noreturn]] static void report_error(int error, Format &&fmt, Params &&...args); +template <typename Format, typename... Params> +[[noreturn]] static void report_error(int error, Format &&fmt, Params &&...args); + static void do_info(parameters_map ¶ms); static void do_verify(parameters_map ¶ms); static void do_create_raw(parameters_map ¶ms); @@ -132,7 +149,6 @@ static void do_create_ld(parameters_map ¶ms); static void do_copy(parameters_map ¶ms); static void do_extract_raw(parameters_map ¶ms); static void do_extract_cd(parameters_map ¶ms); -static void do_extract_dvd(parameters_map ¶ms); static void do_extract_ld(parameters_map ¶ms); static void do_add_metadata(parameters_map ¶ms); static void do_del_metadata(parameters_map ¶ms); @@ -145,6 +161,46 @@ static void do_list_templates(parameters_map ¶ms); // TYPE DEFINITIONS //************************************************************************** +// Allow chdman to show osd_printf_X messages +class chdman_osd_output : public osd_output +{ +public: + chdman_osd_output() { + osd_output::push(this); + } + + ~chdman_osd_output() { + osd_output::pop(this); + } + + void output_callback(osd_output_channel channel, const util::format_argument_pack<char> &args); +}; + +void chdman_osd_output::output_callback(osd_output_channel channel, const util::format_argument_pack<char> &args) +{ + switch (channel) + { + case OSD_OUTPUT_CHANNEL_ERROR: + case OSD_OUTPUT_CHANNEL_WARNING: + util::stream_format(std::cerr, args); + break; + case OSD_OUTPUT_CHANNEL_INFO: + case OSD_OUTPUT_CHANNEL_LOG: + util::stream_format(std::cout, args); + break; + case OSD_OUTPUT_CHANNEL_VERBOSE: + if (OSD_PRINTF_VERBOSE) util::stream_format(std::cout, args); + break; + case OSD_OUTPUT_CHANNEL_DEBUG: +#ifdef MAME_DEBUG + util::stream_format(std::cout, args); +#endif + break; + default: + break; + } +} + // ======================> option_description struct option_description @@ -207,8 +263,7 @@ struct metadata_index_info class fatal_error : public std::exception { public: - fatal_error(int error) - : m_error(error) { } + fatal_error(int error) : m_error(error) { } int error() const { return m_error; } @@ -276,8 +331,7 @@ public: length = m_maxoffset - offset; if (m_file.seek(offset, SEEK_SET)) // FIXME: better error reporting? return 0; - std::size_t actual; - m_file.read(dest, length, actual); // FIXME: check for error return + auto const [err, actual] = read(m_file, dest, length); // FIXME: check for error return return actual; } @@ -296,10 +350,12 @@ class chd_chdfile_compressor : public chd_file_compressor public: // construction/destruction chd_chdfile_compressor(chd_file &file, uint64_t offset = 0, uint64_t maxoffset = ~0) - : m_toc(nullptr), - m_file(file), - m_offset(offset), - m_maxoffset(std::min(maxoffset, file.logical_bytes())) { } + : m_toc(nullptr) + , m_file(file) + , m_offset(offset) + , m_maxoffset(std::min(maxoffset, file.logical_bytes())) + { + } // read interface virtual uint32_t read_data(void *dest, uint64_t offset, uint32_t length) @@ -367,9 +423,11 @@ class chd_cd_compressor : public chd_file_compressor public: // construction/destruction chd_cd_compressor(cdrom_file::toc &toc, cdrom_file::track_input_info &info) - : m_file(), - m_toc(toc), - m_info(info) { } + : m_file() + , m_toc(toc) + , m_info(info) + { + } ~chd_cd_compressor() { @@ -393,6 +451,7 @@ public: { const cdrom_file::track_info &trackinfo = m_toc.tracks[tracknum]; uint64_t endoffs = startoffs + (uint64_t)(trackinfo.frames + trackinfo.extraframes) * cdrom_file::FRAME_SIZE; + if (offset >= startoffs && offset < endoffs) { // if we don't already have this file open, open it now @@ -409,11 +468,11 @@ public: uint64_t bytesperframe = trackinfo.datasize + trackinfo.subsize; uint64_t src_track_start = m_info.track[tracknum].offset; uint64_t src_track_end = src_track_start + bytesperframe * (uint64_t)trackinfo.frames; - uint64_t pad_track_start = src_track_end - ((uint64_t)m_toc.tracks[tracknum].padframes * bytesperframe); - uint64_t split_track_start = pad_track_start - ((uint64_t)m_toc.tracks[tracknum].splitframes * bytesperframe); + uint64_t split_track_start = src_track_end - ((uint64_t)trackinfo.splitframes * bytesperframe); + uint64_t pad_track_start = split_track_start - ((uint64_t)trackinfo.padframes * bytesperframe); // dont split when split-bin read not required - if ((uint64_t)m_toc.tracks[tracknum].splitframes == 0L) + if ((uint64_t)trackinfo.splitframes == 0L) split_track_start = UINT64_MAX; while (length_remaining != 0 && offset < endoffs) @@ -422,7 +481,7 @@ public: uint64_t src_frame_start = src_track_start + ((offset - startoffs) / cdrom_file::FRAME_SIZE) * bytesperframe; // auto-advance next track for split-bin read - if (src_frame_start == split_track_start && m_lastfile.compare(m_info.track[tracknum+1].fname)!=0) + if (src_frame_start >= split_track_start && src_frame_start < src_track_end && m_lastfile.compare(m_info.track[tracknum+1].fname)!=0) { m_file.reset(); m_lastfile = m_info.track[tracknum+1].fname; @@ -434,7 +493,7 @@ public: if (src_frame_start < src_track_end) { // read it in, or pad if we're into the padframes - if (src_frame_start >= pad_track_start) + if (src_frame_start >= pad_track_start && src_frame_start < split_track_start) { memset(dest, 0, bytesperframe); } @@ -447,7 +506,7 @@ public: SEEK_SET); std::size_t count = 0; if (!err) - err = m_file->read(dest, bytesperframe, count); + std::tie(err, count) = read(*m_file, dest, bytesperframe); if (err || (count != bytesperframe)) report_error(1, "Error reading input file (%s)'", m_lastfile); } @@ -493,13 +552,15 @@ class chd_avi_compressor : public chd_file_compressor public: // construction/destruction chd_avi_compressor(avi_file &file, avi_info &info, uint32_t first_frame, uint32_t num_frames) - : m_file(file), - m_info(info), - m_bitmap(info.width, info.height * (info.interlaced ? 2 : 1)), - m_start_frame(first_frame), - m_frame_count(num_frames), - m_ldframedata(num_frames * VBI_PACKED_BYTES), - m_rawdata(info.bytes_per_frame) { } + : m_file(file) + , m_info(info) + , m_bitmap(info.width, info.height * (info.interlaced ? 2 : 1)) + , m_start_frame(first_frame) + , m_frame_count(num_frames) + , m_ldframedata(num_frames * VBI_PACKED_BYTES) + , m_rawdata(info.bytes_per_frame) + { + } // getters const std::vector<uint8_t> &ldframedata() const { return m_ldframedata; } @@ -515,6 +576,7 @@ public: int32_t start_frame = offset / m_info.bytes_per_frame; int32_t end_frame = (offset + length - 1) / m_info.bytes_per_frame; for (int32_t framenum = start_frame; framenum <= end_frame; framenum++) + { if (framenum < m_frame_count) { // determine effective frame number and first/last samples @@ -571,6 +633,7 @@ public: dest += bytes_to_copy; length_remaining -= bytes_to_copy; } + } return length; } @@ -580,11 +643,11 @@ private: avi_file & m_file; avi_info & m_info; bitmap_yuy16 m_bitmap; - uint32_t m_start_frame; - uint32_t m_frame_count; + uint32_t m_start_frame; + uint32_t m_frame_count; std::vector<int16_t> m_audio[8]; - std::vector<uint8_t> m_ldframedata; - std::vector<uint8_t> m_rawdata; + std::vector<uint8_t> m_ldframedata; + std::vector<uint8_t> m_rawdata; }; @@ -598,10 +661,11 @@ static clock_t lastprogress = 0; // default compressors -static const chd_codec_type s_default_raw_compression[4] = { CHD_CODEC_LZMA, CHD_CODEC_ZLIB, CHD_CODEC_HUFFMAN, CHD_CODEC_FLAC }; -static const chd_codec_type s_default_hd_compression[4] = { CHD_CODEC_LZMA, CHD_CODEC_ZLIB, CHD_CODEC_HUFFMAN, CHD_CODEC_FLAC }; -static const chd_codec_type s_default_cd_compression[4] = { CHD_CODEC_CD_LZMA, CHD_CODEC_CD_ZLIB, CHD_CODEC_CD_FLAC }; -static const chd_codec_type s_default_ld_compression[4] = { CHD_CODEC_AVHUFF }; +static const std::array<chd_codec_type, 4> s_no_compression = { CHD_CODEC_NONE, CHD_CODEC_NONE, CHD_CODEC_NONE, CHD_CODEC_NONE }; +static const std::array<chd_codec_type, 4> s_default_raw_compression = { CHD_CODEC_LZMA, CHD_CODEC_ZLIB, CHD_CODEC_HUFFMAN, CHD_CODEC_FLAC }; +static const std::array<chd_codec_type, 4> s_default_hd_compression = { CHD_CODEC_LZMA, CHD_CODEC_ZLIB, CHD_CODEC_HUFFMAN, CHD_CODEC_FLAC }; +static const std::array<chd_codec_type, 4> s_default_cd_compression = { CHD_CODEC_CD_LZMA, CHD_CODEC_CD_ZLIB, CHD_CODEC_CD_FLAC }; +static const std::array<chd_codec_type, 4> s_default_ld_compression = { CHD_CODEC_AVHUFF }; // descriptions for each option @@ -611,6 +675,7 @@ static const option_description s_options[] = { OPTION_INPUT_PARENT, "ip", true, " <filename>: parent file name for input CHD" }, { OPTION_OUTPUT, "o", true, " <filename>: output file name" }, { OPTION_OUTPUT_BIN, "ob", true, " <filename>: output file name for binary data" }, + { OPTION_OUTPUT_SPLITBIN, "sb", false, ": output one binary file per track" }, { OPTION_OUTPUT_FORCE, "f", false, ": force overwriting an existing file" }, { OPTION_OUTPUT_PARENT, "op", true, " <filename>: parent file name for output CHD" }, { OPTION_INPUT_START_BYTE, "isb", true, " <offset>: starting byte offset within the input" }, @@ -623,7 +688,7 @@ static const option_description s_options[] = { OPTION_UNIT_SIZE, "us", true, " <bytes>: size of each unit, in bytes" }, { OPTION_COMPRESSION, "c", true, " <none|type1[,type2[,...]]>: which compression codecs to use (up to 4)" }, { OPTION_IDENT, "id", true, " <filename>: name of ident file to provide CHS information" }, - { OPTION_CHS, "chs", true, " <cylinders,heads,sectors>: specifies CHS values directly" }, + { OPTION_CHS, "chs", true, " <cylinders,heads,sectors>: specifies CHS geometry directly" }, { OPTION_SECTOR_SIZE, "ss", true, " <bytes>: size of each hard disk sector" }, { OPTION_TAG, "t", true, " <tag>: 4-character tag for metadata" }, { OPTION_INDEX, "ix", true, " <index>: indexed instance of this metadata tag" }, @@ -651,7 +716,8 @@ static const command_description s_commands[] = { COMMAND_VERIFY, do_verify, ": verifies a CHD's integrity", { REQUIRED OPTION_INPUT, - OPTION_INPUT_PARENT + OPTION_INPUT_PARENT, + OPTION_FIX } }, @@ -665,8 +731,8 @@ static const command_description s_commands[] = OPTION_INPUT_START_HUNK, OPTION_INPUT_LENGTH_BYTES, OPTION_INPUT_LENGTH_HUNKS, - REQUIRED OPTION_HUNK_SIZE, - REQUIRED OPTION_UNIT_SIZE, + OPTION_HUNK_SIZE, + OPTION_UNIT_SIZE, OPTION_COMPRESSION, OPTION_NUMPROCESSORS } @@ -710,6 +776,11 @@ static const command_description s_commands[] = OPTION_OUTPUT_PARENT, OPTION_OUTPUT_FORCE, REQUIRED OPTION_INPUT, + OPTION_INPUT_START_BYTE, + OPTION_INPUT_START_HUNK, + OPTION_INPUT_LENGTH_BYTES, + OPTION_INPUT_LENGTH_HUNKS, + OPTION_HUNK_SIZE, OPTION_COMPRESSION, OPTION_NUMPROCESSORS } @@ -759,19 +830,23 @@ static const command_description s_commands[] = { REQUIRED OPTION_OUTPUT, OPTION_OUTPUT_BIN, + OPTION_OUTPUT_SPLITBIN, OPTION_OUTPUT_FORCE, REQUIRED OPTION_INPUT, OPTION_INPUT_PARENT, } }, - { COMMAND_EXTRACT_DVD, do_extract_dvd, ": extract DVD file from a CHD input file", + { COMMAND_EXTRACT_DVD, do_extract_raw, ": extract DVD file from a CHD input file", { REQUIRED OPTION_OUTPUT, - OPTION_OUTPUT_BIN, OPTION_OUTPUT_FORCE, REQUIRED OPTION_INPUT, OPTION_INPUT_PARENT, + OPTION_INPUT_START_BYTE, + OPTION_INPUT_START_HUNK, + OPTION_INPUT_LENGTH_BYTES, + OPTION_INPUT_LENGTH_HUNKS } }, @@ -867,7 +942,8 @@ static const hd_template s_hd_templates[] = // report_error - report an error //------------------------------------------------- -template <typename Format, typename... Params> static void report_error(int error, Format &&fmt, Params &&...args) +template <typename Format, typename... Params> +static void report_error(int error, Format &&fmt, Params &&...args) { // output to stderr util::stream_format(std::cerr, std::forward<Format>(fmt), std::forward<Params>(args)...); @@ -883,7 +959,8 @@ template <typename Format, typename... Params> static void report_error(int erro // progress - generic progress callback //------------------------------------------------- -template <typename Format, typename... Params> static void progress(bool forceit, Format &&fmt, Params &&...args) +template <typename Format, typename... Params> +static void progress(bool forceit, Format &&fmt, Params &&...args) { // skip if it hasn't been long enough clock_t curtime = clock(); @@ -904,17 +981,17 @@ template <typename Format, typename... Params> static void progress(bool forceit static int print_help(const std::string &argv0, const char *error = nullptr) { // print the error message first - if (error != nullptr) - fprintf(stderr, "Error: %s\n\n", error); + if (error) + util::stream_format(std::cerr, "Error: %s\n\n", error); // print a summary of each command - printf("Usage:\n"); + util::stream_format(std::cout, "Usage:\n"); for (auto & desc : s_commands) { - printf(" %s %s%s\n", argv0.c_str(), desc.name, desc.description); + util::stream_format(std::cout, " %s %s%s\n", argv0, desc.name, desc.description); } - printf("\nFor help with any command, run:\n"); - printf(" %s %s <command>\n", argv0.c_str(), COMMAND_HELP); + util::stream_format(std::cout, "\nFor help with any command, run:\n"); + util::stream_format(std::cout, " %s %s <command>\n", argv0, COMMAND_HELP); return 1; } @@ -928,11 +1005,11 @@ static int print_help(const std::string &argv0, const command_description &desc, { // print the error message first if (error != nullptr) - fprintf(stderr, "Error: %s\n\n", error); + util::stream_format(std::cerr, "Error: %s\n\n", error); // print usage for this command - printf("Usage:\n"); - printf(" %s %s [options], where valid options are:\n", argv0.c_str(), desc.name); + util::stream_format(std::cout, "Usage:\n"); + util::stream_format(std::cout, " %s %s [options], where valid options are:\n", argv0, desc.name); for (int valid = 0; valid < std::size(desc.valid_options); valid++) { // determine whether we are required @@ -948,10 +1025,10 @@ static int print_help(const std::string &argv0, const command_description &desc, if (strcmp(option, s_option.name) == 0) { const option_description &odesc = s_option; - printf(" --%s", odesc.name); + util::stream_format(std::cout, " --%s", odesc.name); if (odesc.shortname != nullptr) - printf(", -%s", odesc.shortname); - printf("%s%s\n", odesc.description, required ? " (required)" : ""); + util::stream_format(std::cout, ", -%s", odesc.shortname); + util::stream_format(std::cout, "%s%s\n", odesc.description, required ? " (required)" : ""); } } return 1; @@ -1035,10 +1112,17 @@ uint64_t parse_number(const char *string) // compute a best guess CHS value set //------------------------------------------------- -static void guess_chs(std::string *filename, uint64_t filesize, int sectorsize, uint32_t &cylinders, uint32_t &heads, uint32_t §ors, uint32_t &bps) +static void guess_chs( + const std::string *filename, + uint64_t filesize, + int sectorsize, + uint32_t &cylinders, + uint32_t &heads, + uint32_t §ors, + uint32_t &bps) { // if this is a direct physical drive read, handle it specially - if (filename != nullptr && osd_get_physical_drive_geometry(filename->c_str(), &cylinders, &heads, §ors, &bps)) + if (filename && osd_get_physical_drive_geometry(filename->c_str(), &cylinders, &heads, §ors, &bps)) return; // if we have no length to work with, we can't guess @@ -1047,11 +1131,14 @@ static void guess_chs(std::string *filename, uint64_t filesize, int sectorsize, // now find a valid value for (uint32_t totalsectors = filesize / sectorsize; ; totalsectors++) + { for (uint32_t cursectors = 63; cursectors > 1; cursectors--) + { if (totalsectors % cursectors == 0) { uint32_t totalheads = totalsectors / cursectors; for (uint32_t curheads = 16; curheads > 1; curheads--) + { if (totalheads % curheads == 0) { cylinders = totalheads / curheads; @@ -1059,7 +1146,10 @@ static void guess_chs(std::string *filename, uint64_t filesize, int sectorsize, sectors = cursectors; return; } + } } + } + } } @@ -1095,38 +1185,80 @@ static void parse_input_chd_parameters(const parameters_map ¶ms, chd_file &i // parameters in a standard way //------------------------------------------------- -static void parse_input_start_end(const parameters_map ¶ms, uint64_t logical_size, uint32_t hunkbytes, uint32_t framebytes, uint64_t &input_start, uint64_t &input_end) +static std::pair<uint64_t, uint64_t> parse_input_start_end( + const parameters_map ¶ms, + uint64_t logical_size, + uint32_t hunkbytes, + uint32_t framebytes) { - // process start/end if we were provided an input CHD - input_start = 0; - input_end = logical_size; - // process input start - auto input_start_byte_str = params.find(OPTION_INPUT_START_BYTE); - auto input_start_hunk_str = params.find(OPTION_INPUT_START_HUNK); - auto input_start_frame_str = params.find(OPTION_INPUT_START_FRAME); + const auto input_start_byte_str = params.find(OPTION_INPUT_START_BYTE); + const auto input_start_hunk_str = params.find(OPTION_INPUT_START_HUNK); + const auto input_start_frame_str = params.find(OPTION_INPUT_START_FRAME); + uint64_t input_start = 0; if (input_start_byte_str != params.end()) + { + if (input_start_hunk_str != params.end()) + report_error(1, "Start offset cannot be specified in both bytes and hunks"); + if (input_start_frame_str != params.end()) + report_error(1, "Start offset cannot be specified in both bytes and frames"); input_start = parse_number(input_start_byte_str->second->c_str()); - if (input_start_hunk_str != params.end()) + } + else if (input_start_hunk_str != params.end()) + { + if (input_start_frame_str != params.end()) + report_error(1, "Start offset cannot be specified in both hunks and frames"); input_start = parse_number(input_start_hunk_str->second->c_str()) * hunkbytes; - if (input_start_frame_str != params.end()) + } + else if (input_start_frame_str != params.end()) + { input_start = parse_number(input_start_frame_str->second->c_str()) * framebytes; - if (input_start >= input_end) - report_error(1, "Input start offset greater than input file size"); + } // process input length - auto input_length_bytes_str = params.find(OPTION_INPUT_LENGTH_BYTES); + const auto input_length_bytes_str = params.find(OPTION_INPUT_LENGTH_BYTES); auto input_length_hunks_str = params.find(OPTION_INPUT_LENGTH_HUNKS); auto input_length_frames_str = params.find(OPTION_INPUT_LENGTH_FRAMES); - uint64_t input_length = input_end; + std::optional<uint64_t> input_length; if (input_length_bytes_str != params.end()) + { + if (input_length_hunks_str != params.end()) + report_error(1, "Length cannot be specified in both bytes and hunks"); + if (input_length_frames_str != params.end()) + report_error(1, "Length cannot be specified in both bytes and frames"); input_length = parse_number(input_length_bytes_str->second->c_str()); - if (input_length_hunks_str != params.end()) + } + else if (input_length_hunks_str != params.end()) + { + if (input_length_frames_str != params.end()) + report_error(1, "Length cannot be specified in both hunks and frames"); input_length = parse_number(input_length_hunks_str->second->c_str()) * hunkbytes; - if (input_length_frames_str != params.end()) + } + else if (input_length_frames_str != params.end()) + { input_length = parse_number(input_length_frames_str->second->c_str()) * framebytes; - if (input_start + input_length < input_end) - input_end = input_start + input_length; + } + + // check that offsets are within input + if (input_start >= logical_size) + report_error(1, "Input start offset is beyond end of input"); + if (input_length && ((input_start + *input_length) > logical_size)) + report_error(1, "Input length is larger than available input from start offset"); + return std::make_pair(input_start, input_length ? (input_start + *input_length) : logical_size); +} + +static std::tuple<uint64_t, uint64_t, uint64_t> parse_input_start_end( + const parameters_map ¶ms, + util::random_read &input_file, + uint32_t hunkbytes, + uint32_t framebytes) +{ + uint64_t input_size = 0; + const std::error_condition err = input_file.length(input_size); + if (err) + report_error(1, "Error getting size of input file: %s", err.message()); + const auto [input_start, input_end] = parse_input_start_end(params, input_size, hunkbytes, framebytes); + return std::make_tuple(input_size, input_start, input_end); } @@ -1136,7 +1268,7 @@ static void parse_input_start_end(const parameters_map ¶ms, uint64_t logical // unless --force is specified //------------------------------------------------- -static void check_existing_output_file(const parameters_map ¶ms, const char *filename) +static void check_existing_output_file(const parameters_map ¶ms, std::string_view filename) { if (params.find(OPTION_OUTPUT_FORCE) == params.end()) { @@ -1156,10 +1288,10 @@ static void check_existing_output_file(const parameters_map ¶ms, const char // standard set of output CHD parameters //------------------------------------------------- -static std::string *parse_output_chd_parameters(const parameters_map ¶ms, chd_file &output_parent_chd) +static const std::string *parse_output_chd_parameters(const parameters_map ¶ms, chd_file &output_parent_chd) { // process output parent file - auto output_chd_parent_str = params.find(OPTION_OUTPUT_PARENT); + const auto output_chd_parent_str = params.find(OPTION_OUTPUT_PARENT); if (output_chd_parent_str != params.end()) { std::error_condition err = output_parent_chd.open(*output_chd_parent_str->second); @@ -1168,10 +1300,11 @@ static std::string *parse_output_chd_parameters(const parameters_map ¶ms, ch } // process output file - auto output_chd_str = params.find(OPTION_OUTPUT); - if (output_chd_str != params.end()) - check_existing_output_file(params, output_chd_str->second->c_str()); - return (output_chd_str != params.end()) ? output_chd_str->second : nullptr; + const auto output_chd_str = params.find(OPTION_OUTPUT); + if (output_chd_str == params.end()) + return nullptr; + check_existing_output_file(params, *output_chd_str->second); + return output_chd_str->second; } @@ -1180,17 +1313,32 @@ static std::string *parse_output_chd_parameters(const parameters_map ¶ms, ch // parameter in a standard way //------------------------------------------------- -static void parse_hunk_size(const parameters_map ¶ms, uint32_t required_granularity, uint32_t &hunk_size) +static uint32_t parse_hunk_size( + const parameters_map ¶ms, + const chd_file &output_parent, + uint32_t required_granularity, + uint32_t default_size) { - auto hunk_size_str = params.find(OPTION_HUNK_SIZE); + const auto hunk_size_str = params.find(OPTION_HUNK_SIZE); + uint32_t hunk_size = default_size; if (hunk_size_str != params.end()) { hunk_size = parse_number(hunk_size_str->second->c_str()); - if (hunk_size < 16 || hunk_size > 1024 * 1024) - report_error(1, "Invalid hunk size"); - if (hunk_size % required_granularity != 0) - report_error(1, "Hunk size is not an even multiple of %d", required_granularity); + if (output_parent.opened() && (output_parent.hunk_bytes() != hunk_size)) + report_error(1, "Specified hunk size %u bytes does not match output parent CHD hunk size %u bytes", hunk_size, output_parent.hunk_bytes()); + if (hunk_size < HUNK_SIZE_MIN) + report_error(1, "Invalid hunk size (minimum %u)", HUNK_SIZE_MIN); + if (hunk_size > HUNK_SIZE_MAX) + report_error(1, "Invalid hunk size (maximum %u)", HUNK_SIZE_MAX); + } + else if (output_parent.opened()) + { + hunk_size = output_parent.hunk_bytes(); } + + if (hunk_size % required_granularity) + report_error(1, "Hunk size %u bytes is not a whole multiple of %u", hunk_size, required_granularity); + return hunk_size; } @@ -1199,15 +1347,18 @@ static void parse_hunk_size(const parameters_map ¶ms, uint32_t required_gran // compression parameter string //------------------------------------------------- -static void parse_compression(const parameters_map ¶ms, chd_codec_type compression[4]) +static void parse_compression(const parameters_map ¶ms, const std::array<chd_codec_type, 4> &defaults, const chd_file &output_parent, chd_codec_type compression[4]) { + // TODO: should we default to the same compression as the output parent? + std::copy(std::begin(defaults), std::end(defaults), compression); + // see if anything was specified - auto compression_str = params.find(OPTION_COMPRESSION); + const auto compression_str = params.find(OPTION_COMPRESSION); if (compression_str == params.end()) return; // special case: 'none' - if (compression_str->second->compare("none")==0) + if (*compression_str->second == "none") { compression[0] = compression[1] = compression[2] = compression[3] = CHD_CODEC_NONE; return; @@ -1286,6 +1437,49 @@ static std::string compression_string(chd_codec_type compression[4]) //------------------------------------------------- +// open_input_file - open input file if specified +//------------------------------------------------- + +static std::pair<util::core_file::ptr, const std::string *> open_input_file(const parameters_map ¶ms) +{ + const auto path = params.find(OPTION_INPUT); + if (path == params.end()) + return std::make_pair(nullptr, nullptr); + + util::core_file::ptr file; + const std::error_condition err = util::core_file::open(*path->second, OPEN_FLAG_READ, file); + if (err) + report_error(1, "Unable to open input file (%s): %s", *path->second, err.message()); + + return std::make_pair(std::move(file), path->second); +} + + +//------------------------------------------------- +// create_output_chd - open output CHD with or +// without parent CHD file +//------------------------------------------------- + +static void create_output_chd( + chd_file_compressor &compressor, + std::string_view path, + uint64_t logical_size, + uint32_t hunk_size, + uint32_t unit_size, + const chd_codec_type (&compression)[4], + chd_file &parent) +{ + std::error_condition err; + if (parent.opened()) + err = compressor.create(path, logical_size, hunk_size, compression, parent); + else + err = compressor.create(path, logical_size, hunk_size, unit_size, compression); + if (err) + report_error(1, "Error creating CHD file (%s): %s", path, err.message()); +} + + +//------------------------------------------------- // compress_common - standard compression loop //------------------------------------------------- @@ -1317,62 +1511,19 @@ static void compress_common(chd_file_compressor &chd) // to a CUE file //------------------------------------------------- -void output_track_metadata(int mode, util::core_file &file, int tracknum, const cdrom_file::track_info &info, const std::string &filename, uint32_t frameoffs, uint64_t discoffs) +void output_track_metadata(int mode, util::core_file &file, int tracknum, const cdrom_file::track_info &info, const std::string &filename, uint32_t frameoffs, uint64_t outputoffs) { if (mode == MODE_GDI) { - int mode = 0, size = 2048; - - switch (info.trktype) - { - case cdrom_file::CD_TRACK_MODE1: - mode = 4; - size = 2048; - break; - - case cdrom_file::CD_TRACK_MODE1_RAW: - mode = 4; - size = 2352; - break; - - case cdrom_file::CD_TRACK_MODE2: - mode = 4; - size = 2336; - break; - - case cdrom_file::CD_TRACK_MODE2_FORM1: - mode = 4; - size = 2048; - break; - - case cdrom_file::CD_TRACK_MODE2_FORM2: - mode = 4; - size = 2324; - break; - - case cdrom_file::CD_TRACK_MODE2_FORM_MIX: - mode = 4; - size = 2336; - break; - - case cdrom_file::CD_TRACK_MODE2_RAW: - mode = 4; - size = 2352; - break; - - case cdrom_file::CD_TRACK_AUDIO: - mode = 0; - size = 2352; - break; - } + const int tracktype = info.trktype == cdrom_file::CD_TRACK_AUDIO ? 0 : 4; const bool needquote = filename.find(' ') != std::string::npos; const char *const quotestr = needquote ? "\"" : ""; - file.printf("%d %d %d %d %s%s%s %d\n", tracknum+1, frameoffs, mode, size, quotestr, filename, quotestr, discoffs); + file.printf("%d %d %d %d %s%s%s %d\n", tracknum+1, frameoffs, tracktype, info.datasize, quotestr, filename, quotestr, outputoffs); } else if (mode == MODE_CUEBIN) { - // first track specifies the file - if (tracknum == 0) + // specify a new file when writing to the beginning of a file + if (outputoffs == 0) file.printf("FILE \"%s\" BINARY\n", filename); // determine submode @@ -1447,11 +1598,10 @@ void output_track_metadata(int mode, util::core_file &file, int tracknum, const if (info.pregap > 0) file.printf("ZERO %s %s\n", modesubmode, msf_string_from_frames(info.pregap)); - // all tracks but the first one have a file offset - if (tracknum > 0) - file.printf("DATAFILE \"%s\" #%d %s // length in bytes: %d\n", filename, uint32_t(discoffs), msf_string_from_frames(info.frames), info.frames * (info.datasize + info.subsize)); - else + if (outputoffs == 0) file.printf("DATAFILE \"%s\" %s // length in bytes: %d\n", filename, msf_string_from_frames(info.frames), info.frames * (info.datasize + info.subsize)); + else + file.printf("DATAFILE \"%s\" #%d %s // length in bytes: %d\n", filename, uint32_t(outputoffs), msf_string_from_frames(info.frames), info.frames * (info.datasize + info.subsize)); // tracks with pregaps get a START marker too if (info.pregap > 0) @@ -1476,8 +1626,8 @@ static void do_info(parameters_map ¶ms) parse_input_chd_parameters(params, input_chd, input_parent_chd); // print filename and version - printf("Input file: %s\n", params.find(OPTION_INPUT)->second->c_str()); - printf("File Version: %d\n", input_chd.version()); + util::stream_format(std::cout, "Input file: %s\n", *params.find(OPTION_INPUT)->second); + util::stream_format(std::cout, "File Version: %d\n", input_chd.version()); if (input_chd.version() < 3) report_error(1, "Unsupported version (%d); use an older chdman to upgrade to version 3 or later", input_chd.version()); @@ -1485,27 +1635,27 @@ static void do_info(parameters_map ¶ms) chd_codec_type compression[4] = { input_chd.compression(0), input_chd.compression(1), input_chd.compression(2), input_chd.compression(3) }; uint64_t filesize = 0; input_chd.file().length(filesize); - printf("Logical size: %s bytes\n", big_int_string(input_chd.logical_bytes()).c_str()); - printf("Hunk Size: %s bytes\n", big_int_string(input_chd.hunk_bytes()).c_str()); - printf("Total Hunks: %s\n", big_int_string(input_chd.hunk_count()).c_str()); - printf("Unit Size: %s bytes\n", big_int_string(input_chd.unit_bytes()).c_str()); - printf("Total Units: %s\n", big_int_string(input_chd.unit_count()).c_str()); - printf("Compression: %s\n", compression_string(compression).c_str()); - printf("CHD size: %s bytes\n", big_int_string(filesize).c_str()); + util::stream_format(std::cout, "Logical size: %s bytes\n", big_int_string(input_chd.logical_bytes())); + util::stream_format(std::cout, "Hunk Size: %s bytes\n", big_int_string(input_chd.hunk_bytes())); + util::stream_format(std::cout, "Total Hunks: %s\n", big_int_string(input_chd.hunk_count())); + util::stream_format(std::cout, "Unit Size: %s bytes\n", big_int_string(input_chd.unit_bytes())); + util::stream_format(std::cout, "Total Units: %s\n", big_int_string(input_chd.unit_count())); + util::stream_format(std::cout, "Compression: %s\n", compression_string(compression)); + util::stream_format(std::cout, "CHD size: %s bytes\n", big_int_string(filesize)); if (compression[0] != CHD_CODEC_NONE) - printf("Ratio: %.1f%%\n", 100.0 * double(filesize) / double(input_chd.logical_bytes())); + util::stream_format(std::cout, "Ratio: %.1f%%\n", 100.0 * double(filesize) / double(input_chd.logical_bytes())); - // add SHA1 output + // add SHA-1 output util::sha1_t overall = input_chd.sha1(); if (overall != util::sha1_t::null) { - printf("SHA1: %s\n", overall.as_string().c_str()); + util::stream_format(std::cout, "SHA1: %s\n", overall.as_string()); if (input_chd.version() >= 4) - printf("Data SHA1: %s\n", input_chd.raw_sha1().as_string().c_str()); + util::stream_format(std::cout, "Data SHA1: %s\n", input_chd.raw_sha1().as_string()); } util::sha1_t parent = input_chd.parent_sha1(); if (parent != util::sha1_t::null) - printf("Parent SHA1: %s\n", parent.as_string().c_str()); + util::stream_format(std::cout, "Parent SHA1: %s\n", parent.as_string()); // print out metadata std::vector<uint8_t> buffer; @@ -1538,18 +1688,18 @@ static void do_info(parameters_map ¶ms) // print either a string representation or a hex representation of the tag if (isprint((metatag >> 24) & 0xff) && isprint((metatag >> 16) & 0xff) && isprint((metatag >> 8) & 0xff) && isprint(metatag & 0xff)) - printf("Metadata: Tag='%c%c%c%c' Index=%d Length=%d bytes\n", (metatag >> 24) & 0xff, (metatag >> 16) & 0xff, (metatag >> 8) & 0xff, metatag & 0xff, metaindex, int(buffer.size())); + util::stream_format(std::cout, "Metadata: Tag='%c%c%c%c' Index=%d Length=%d bytes\n", (metatag >> 24) & 0xff, (metatag >> 16) & 0xff, (metatag >> 8) & 0xff, metatag & 0xff, metaindex, buffer.size()); else - printf("Metadata: Tag=%08x Index=%d Length=%d bytes\n", metatag, metaindex, int(buffer.size())); - printf(" "); + util::stream_format(std::cout, "Metadata: Tag=%08x Index=%d Length=%d bytes\n", metatag, metaindex, buffer.size()); + util::stream_format(std::cout, " "); uint32_t count = buffer.size(); // limit output to 60 characters of metadata if not verbose if (!verbose) count = std::min(60U, count); for (int chnum = 0; chnum < count; chnum++) - printf("%c", isprint(uint8_t(buffer[chnum])) ? buffer[chnum] : '.'); - printf("\n"); + util::stream_format(std::cout, "%c", isprint(uint8_t(buffer[chnum])) ? buffer[chnum] : '.'); + util::stream_format(std::cout, "\n"); } // print compression stats if verbose @@ -1581,9 +1731,9 @@ static void do_info(parameters_map ¶ms) } // output the stats - printf("\n"); - printf(" Hunks Percent Name\n"); - printf("---------- ------- ------------------------------------\n"); + util::stream_format(std::cout, "\n"); + util::stream_format(std::cout, " Hunks Percent Name\n"); + util::stream_format(std::cout, "---------- ------- ------------------------------------\n"); for (int comptype = 0; comptype < std::size(compression_types); comptype++) if (compression_types[comptype] != 0) { @@ -1603,8 +1753,8 @@ static void do_info(parameters_map ¶ms) } // output the stats - printf("%10s %5.1f%% %-40s\n", - big_int_string(compression_types[comptype]).c_str(), + util::stream_format(std::cout, "%10s %5.1f%% %-40s\n", + big_int_string(compression_types[comptype]), 100.0 * double(compression_types[comptype]) / double(input_chd.hunk_count()), name); } @@ -1613,7 +1763,7 @@ static void do_info(parameters_map ¶ms) //------------------------------------------------- -// do_verify - validate the SHA1 on a CHD +// do_verify - validate the SHA-1 on a CHD //------------------------------------------------- static void do_verify(parameters_map ¶ms) @@ -1623,7 +1773,7 @@ static void do_verify(parameters_map ¶ms) chd_file input_chd; parse_input_chd_parameters(params, input_chd, input_parent_chd); - // only makes sense for compressed CHDs with valid SHA1's + // only makes sense for compressed CHDs with valid SHA-1's if (!input_chd.compressed()) report_error(0, "No verification to be done; CHD is uncompressed"); util::sha1_t raw_sha1 = (input_chd.version() <= 3) ? input_chd.sha1() : input_chd.raw_sha1(); @@ -1654,36 +1804,41 @@ static void do_verify(parameters_map ¶ms) // finish up if (raw_sha1 != computed_sha1) { - fprintf(stderr, "Error: Raw SHA1 in header = %s\n", raw_sha1.as_string().c_str()); - fprintf(stderr, " actual SHA1 = %s\n", computed_sha1.as_string().c_str()); + util::stream_format(std::cerr, "Error: Raw SHA1 in header = %s\n", raw_sha1.as_string()); + util::stream_format(std::cerr, " actual SHA1 = %s\n", computed_sha1.as_string()); // fix it if requested; this also fixes the overall one so we don't need to do any more if (params.find(OPTION_FIX) != params.end()) { - input_chd.set_raw_sha1(computed_sha1); - printf("SHA-1 updated to correct value in input CHD\n"); + std::error_condition err = input_chd.set_raw_sha1(computed_sha1); + if (err) + report_error(1, "Error updating SHA1: %s", err.message()); + util::stream_format(std::cout, "SHA1 updated to correct value in input CHD\n"); } } else { - printf("Raw SHA1 verification successful!\n"); + util::stream_format(std::cout, "Raw SHA1 verification successful!\n"); // now include the metadata for >= v4 if (input_chd.version() >= 4) { util::sha1_t computed_overall_sha1 = input_chd.compute_overall_sha1(computed_sha1); if (input_chd.sha1() == computed_overall_sha1) - printf("Overall SHA1 verification successful!\n"); + util::stream_format(std::cout, "Overall SHA1 verification successful!\n"); else { - fprintf(stderr, "Error: Overall SHA1 in header = %s\n", input_chd.sha1().as_string().c_str()); - fprintf(stderr, " actual SHA1 = %s\n", computed_overall_sha1.as_string().c_str()); + util::stream_format(std::cerr, "Error: Overall SHA1 in header = %s\n", input_chd.sha1().as_string()); + util::stream_format(std::cerr, " actual SHA1 = %s\n", computed_overall_sha1.as_string()); // fix it if requested if (params.find(OPTION_FIX) != params.end()) { input_chd.set_raw_sha1(computed_sha1); - printf("SHA-1 updated to correct value in input CHD\n"); + std::error_condition err = input_chd.set_raw_sha1(computed_sha1); + if (err) + report_error(1, "Error updating SHA1: %s", err.message()); + util::stream_format(std::cout, "SHA1 updated to correct value in input CHD\n"); } } } @@ -1699,22 +1854,11 @@ static void do_verify(parameters_map ¶ms) static void do_create_raw(parameters_map ¶ms) { // process input file - util::core_file::ptr input_file; - auto input_file_str = params.find(OPTION_INPUT); - if (input_file_str != params.end()) - { - std::error_condition const filerr = util::core_file::open(*input_file_str->second, OPEN_FLAG_READ, input_file); - if (filerr) - report_error(1, "Unable to open file (%s): %s", *input_file_str->second, filerr.message()); - } + auto [input_file, input_file_str] = open_input_file(params); // process output CHD chd_file output_parent; - std::string *output_chd_str = parse_output_chd_parameters(params, output_parent); - - // process hunk size - uint32_t hunk_size = output_parent.opened() ? output_parent.hunk_bytes() : 0; - parse_hunk_size(params, 1, hunk_size); + const auto output_chd_str = parse_output_chd_parameters(params, output_parent); // process unit size uint32_t unit_size = output_parent.opened() ? output_parent.unit_bytes() : 0; @@ -1722,51 +1866,49 @@ static void do_create_raw(parameters_map ¶ms) if (unit_size_str != params.end()) { unit_size = parse_number(unit_size_str->second->c_str()); - if (hunk_size % unit_size != 0) - report_error(1, "Unit size is not an even divisor of the hunk size"); + if (output_parent.opened() && (output_parent.unit_bytes() != unit_size)) + report_error(1, "Specified unit size %u bytes does not match output parent CHD unit size %u bytes", unit_size, output_parent.unit_bytes()); } + else if (!output_parent.opened()) + { + report_error(1, "Unit size must be specified if no output parent CHD is supplied"); + } + + // process hunk size + const uint32_t hunk_size = parse_hunk_size(params, output_parent, unit_size, std::max((4096 / unit_size) * unit_size, unit_size)); // process input start/end (needs to know hunk_size) - uint64_t input_start; - uint64_t input_end; - uint64_t input_size = 0; - input_file->length(input_size); // FIXME: check error return - parse_input_start_end(params, input_size, hunk_size, hunk_size, input_start, input_end); + const auto [input_size, input_start, input_end] = parse_input_start_end(params, *input_file, hunk_size, hunk_size); + if ((input_end - input_start) % unit_size) + report_error(1, "Data size %s is not divisible by unit size %d", big_int_string(input_end - input_start), unit_size); // process compression chd_codec_type compression[4]; - memcpy(compression, s_default_raw_compression, sizeof(compression)); - parse_compression(params, compression); + parse_compression(params, s_default_raw_compression, output_parent, compression); // process numprocessors parse_numprocessors(params); // print some info - printf("Output CHD: %s\n", output_chd_str->c_str()); + util::stream_format(std::cout, "Output CHD: %s\n", *output_chd_str); 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()); + util::stream_format(std::cout, "Parent CHD: %s\n", *params.find(OPTION_OUTPUT_PARENT)->second); + util::stream_format(std::cout, "Input file: %s\n", *input_file_str); if (input_start != 0 || input_end != input_size) { - printf("Input start: %s\n", big_int_string(input_start).c_str()); - printf("Input length: %s\n", big_int_string(input_end - input_start).c_str()); + util::stream_format(std::cout, "Input start: %s\n", big_int_string(input_start)); + util::stream_format(std::cout, "Input length: %s\n", big_int_string(input_end - input_start)); } - printf("Compression: %s\n", compression_string(compression).c_str()); - printf("Hunk size: %s\n", big_int_string(hunk_size).c_str()); - printf("Logical size: %s\n", big_int_string(input_end - input_start).c_str()); + util::stream_format(std::cout, "Compression: %s\n", compression_string(compression)); + util::stream_format(std::cout, "Hunk size: %s\n", big_int_string(hunk_size)); + util::stream_format(std::cout, "Logical size: %s\n", big_int_string(input_end - input_start)); // catch errors so we can close & delete the output file try { // create the new CHD - std::unique_ptr<chd_file_compressor> chd(new chd_rawfile_compressor(*input_file, input_start, input_end)); - std::error_condition err; - if (output_parent.opened()) - err = chd->create(output_chd_str->c_str(), input_end - input_start, hunk_size, compression, output_parent); - else - err = chd->create(output_chd_str->c_str(), input_end - input_start, hunk_size, unit_size, compression); - if (err) - report_error(1, "Error creating CHD file (%s): %s", output_chd_str, err.message()); + auto chd = std::make_unique<chd_rawfile_compressor>(*input_file, input_start, input_end); + create_output_chd(*chd, *output_chd_str, input_end - input_start, hunk_size, unit_size, compression, output_parent); // if we have a parent, copy forward all the metadata if (output_parent.opened()) @@ -1778,9 +1920,7 @@ static void do_create_raw(parameters_map ¶ms) catch (...) { // delete the output file - auto output_chd_str = params.find(OPTION_OUTPUT); - if (output_chd_str != params.end()) - osd_file::remove(*output_chd_str->second); + osd_file::remove(*output_chd_str); throw; } } @@ -1794,79 +1934,93 @@ static void do_create_raw(parameters_map ¶ms) static void do_create_hd(parameters_map ¶ms) { // process input file - util::core_file::ptr input_file; - auto input_file_str = params.find(OPTION_INPUT); - if (input_file_str != params.end()) - { - std::error_condition const filerr = util::core_file::open(*input_file_str->second, OPEN_FLAG_READ, input_file); - if (filerr) - report_error(1, "Unable to open file (%s): %s", *input_file_str->second, filerr.message()); - } + auto [input_file, input_file_str] = open_input_file(params); // process output CHD chd_file output_parent; - std::string *output_chd_str = parse_output_chd_parameters(params, output_parent); + const auto output_chd_str = parse_output_chd_parameters(params, output_parent); - // process sectorsize + // process template + uint32_t cylinders = 0; + uint32_t heads = 0; + uint32_t sectors = 0; uint32_t sector_size = output_parent.opened() ? output_parent.unit_bytes() : IDE_SECTOR_SIZE; + const auto template_str = params.find(OPTION_TEMPLATE); + uint32_t template_id = 0; + if (template_str != params.end()) + { + if (output_parent.opened()) + report_error(1, "Template cannot be used when a parent CHD is supplied"); + template_id = parse_number(template_str->second->c_str()); + if (template_id >= std::size(s_hd_templates)) + report_error(1, "Template '%s' is invalid\n", *template_str->second); + + cylinders = s_hd_templates[template_id].cylinders; + heads = s_hd_templates[template_id].heads; + sectors = s_hd_templates[template_id].sectors; + sector_size = s_hd_templates[template_id].sector_size; + } + + // process CHS + const auto chs_str = params.find(OPTION_CHS); + if (chs_str != params.end()) + { + if (template_str != params.end()) + report_error(1, "CHS geometry cannot be specified separately when a template is specified"); + if (output_parent.opened()) + report_error(1, "CHS geometry cannot be specified when a parent CHD is supplied"); + if (sscanf(chs_str->second->c_str(), "%u,%u,%u", &cylinders, &heads, §ors) != 3) + report_error(1, "Invalid CHS string; must be of the form <cylinders>,<heads>,<sectors>"); + } + + // process sector size auto sectorsize_str = params.find(OPTION_SECTOR_SIZE); if (sectorsize_str != params.end()) { - if (output_parent.opened()) - report_error(1, "Sector size does not apply when creating a diff from the parent"); + if (template_str != params.end()) + report_error(1, "Sector size cannot be specified separately when a template is specified"); sector_size = parse_number(sectorsize_str->second->c_str()); } + if (output_parent.opened() && (output_parent.unit_bytes() != sector_size)) + report_error(1, "Sector size %u bytes does not match output parent CHD sector size %u bytes", sector_size, output_parent.unit_bytes()); // process hunk size (needs to know sector_size) - uint32_t hunk_size = output_parent.opened() ? output_parent.hunk_bytes() : std::max((4096 / sector_size) * sector_size, sector_size); - parse_hunk_size(params, sector_size, hunk_size); + const uint32_t hunk_size = parse_hunk_size(params, output_parent, sector_size, std::max((4096 / sector_size) * sector_size, sector_size)); // process input start/end (needs to know hunk_size) uint64_t filesize = 0; + uint64_t input_size = 0; uint64_t input_start = 0; uint64_t input_end = 0; if (input_file) { - uint64_t input_size = 0; - input_file->length(input_size); // FIXME: check error return - parse_input_start_end(params, input_size, hunk_size, hunk_size, input_start, input_end); + std::tie(input_size, input_start, input_end) = parse_input_start_end(params, *input_file, hunk_size, hunk_size); filesize = input_end - input_start; + if (params.find(OPTION_SIZE) != params.end()) + report_error(1, "Size cannot be specified when an input file is supplied"); } else { - auto size_str = params.find(OPTION_SIZE); + const auto size_str = params.find(OPTION_SIZE); if (size_str != params.end()) { - if (sscanf(size_str->second->c_str(), "%" I64FMT"d", &filesize) != 1) - report_error(1, "Invalid size string"); + if (sscanf(size_str->second->c_str(), "%" I64FMT"u", &filesize) != 1) + report_error(1, "Invalid size specified"); } + if ((params.find(OPTION_INPUT_START_BYTE) != params.end()) || (params.find(OPTION_INPUT_START_HUNK) != params.end()) || + (params.find(OPTION_INPUT_LENGTH_BYTES) != params.end()) || (params.find(OPTION_INPUT_LENGTH_HUNKS) != params.end())) + report_error(1, "Input start/length cannot be specified when no input file is supplied"); } // process compression chd_codec_type compression[4]; - memcpy(compression, s_default_hd_compression, sizeof(compression)); - if (!input_file) - compression[0] = compression[1] = compression[2] = compression[3] = CHD_CODEC_NONE; - parse_compression(params, compression); - if (!input_file && compression[0] != CHD_CODEC_NONE) - report_error(1, "Blank hard disks must be uncompressed"); + parse_compression(params, input_file ? s_default_hd_compression : s_no_compression, output_parent, compression); + if (!input_file && (compression[0] != CHD_CODEC_NONE)) + report_error(1, "Blank hard disk images must be uncompressed"); // process numprocessors parse_numprocessors(params); - // process chs - uint32_t cylinders = 0; - uint32_t heads = 0; - uint32_t sectors = 0; - auto chs_str = params.find(OPTION_CHS); - if (chs_str != params.end()) - { - if (output_parent.opened()) - report_error(1, "CHS does not apply when creating a diff from the parent"); - if (sscanf(chs_str->second->c_str(), "%d,%d,%d", &cylinders, &heads, §ors) != 3) - report_error(1, "Invalid CHS string; must be of the form <cylinders>,<heads>,<sectors>"); - } - // process ident std::vector<uint8_t> identdata; if (output_parent.opened()) @@ -1887,27 +2041,10 @@ static void do_create_hd(parameters_map ¶ms) sectors = get_u16le(&identdata[12]); // ignore CHS for > 8GB drives - if (cylinders * heads * sectors >= 16514064) + if (cylinders * heads * sectors >= 16'514'064) cylinders = 0; } - // process template - auto template_str = params.find(OPTION_TEMPLATE); - if (template_str != params.end()) - { - uint32_t id = parse_number(template_str->second->c_str()); - - if (id >= std::size(s_hd_templates)) - report_error(1, "Template '%d' is invalid\n", id); - - cylinders = s_hd_templates[id].cylinders; - heads = s_hd_templates[id].heads; - sectors = s_hd_templates[id].sectors; - sector_size = s_hd_templates[id].sector_size; - - printf("Template: %s %s\n", s_hd_templates[id].manufacturer, s_hd_templates[id].model); - } - // extract geometry from the parent if we have one if (output_parent.opened() && cylinders == 0) { @@ -1919,58 +2056,55 @@ static void do_create_hd(parameters_map ¶ms) } // validate the size - if (filesize % sector_size != 0) - report_error(1, "Data size is not divisible by sector size %d", sector_size); + if (filesize % sector_size) + report_error(1, "Data size %s is not divisible by sector size %u", big_int_string(input_end - input_start), sector_size); // if no CHS values, try to guess them if (cylinders == 0) { if (!input_file && filesize == 0) - report_error(1, "Blank hard drives must specify either a length or a set of CHS values"); - guess_chs((input_file_str != params.end()) ? input_file_str->second : nullptr, filesize, sector_size, cylinders, heads, sectors, sector_size); + report_error(1, "Length or CHS geometry must be specified when creating a blank hard disk image"); + guess_chs(input_file_str, filesize, sector_size, cylinders, heads, sectors, sector_size); } uint32_t totalsectors = cylinders * heads * sectors; // print some info - printf("Output CHD: %s\n", output_chd_str->c_str()); + util::stream_format(std::cout, "Output CHD: %s\n", *output_chd_str); if (output_parent.opened()) - printf("Parent CHD: %s\n", params.find(OPTION_OUTPUT_PARENT)->second->c_str()); + util::stream_format(std::cout, "Parent CHD: %s\n", *params.find(OPTION_OUTPUT_PARENT)->second); if (input_file) { - uint64_t input_size = 0; - input_file->length(input_size); // FIXME: check error return - printf("Input file: %s\n", input_file_str->second->c_str()); + util::stream_format(std::cout, "Input file: %s\n", *input_file_str); if (input_start != 0 || input_end != input_size) { - printf("Input start: %s\n", big_int_string(input_start).c_str()); - printf("Input length: %s\n", big_int_string(filesize).c_str()); + util::stream_format(std::cout, "Input start: %s\n", big_int_string(input_start)); + util::stream_format(std::cout, "Input length: %s\n", big_int_string(filesize)); } } - printf("Compression: %s\n", compression_string(compression).c_str()); - printf("Cylinders: %d\n", cylinders); - printf("Heads: %d\n", heads); - printf("Sectors: %d\n", sectors); - printf("Bytes/sector: %d\n", sector_size); - printf("Sectors/hunk: %d\n", hunk_size / sector_size); - printf("Logical size: %s\n", big_int_string(uint64_t(totalsectors) * uint64_t(sector_size)).c_str()); + util::stream_format(std::cout, "Compression: %s\n", compression_string(compression)); + if (template_str != params.end()) + util::stream_format(std::cout, "Template: %s %s\n", s_hd_templates[template_id].manufacturer, s_hd_templates[template_id].model); + util::stream_format(std::cout, "Cylinders: %u\n", cylinders); + util::stream_format(std::cout, "Heads: %u\n", heads); + util::stream_format(std::cout, "Sectors: %u\n", sectors); + util::stream_format(std::cout, "Bytes/sector: %u\n", sector_size); + util::stream_format(std::cout, "Sectors/hunk: %u\n", hunk_size / sector_size); + util::stream_format(std::cout, "Logical size: %s\n", big_int_string(uint64_t(totalsectors) * uint64_t(sector_size))); // catch errors so we can close & delete the output file try { // create the new hard drive std::unique_ptr<chd_file_compressor> chd; - if (input_file) chd.reset(new chd_rawfile_compressor(*input_file, input_start, input_end)); - else chd.reset(new chd_zero_compressor(input_start, input_end)); - std::error_condition err; - if (output_parent.opened()) - err = chd->create(output_chd_str->c_str(), uint64_t(totalsectors) * uint64_t(sector_size), hunk_size, compression, output_parent); + if (input_file) + chd.reset(new chd_rawfile_compressor(*input_file, input_start, input_end)); else - err = chd->create(output_chd_str->c_str(), uint64_t(totalsectors) * uint64_t(sector_size), hunk_size, sector_size, compression); - if (err) - report_error(1, "Error creating CHD file (%s): %s", output_chd_str, err.message()); + chd.reset(new chd_zero_compressor(input_start, input_end)); + create_output_chd(*chd, *output_chd_str, uint64_t(totalsectors) * sector_size, hunk_size, sector_size, compression, output_parent); // add the standard hard disk metadata - std::string metadata = string_format(HARD_DISK_METADATA_FORMAT, cylinders, heads, sectors, sector_size); + std::string metadata = string_format(HARD_DISK_METADATA_FORMAT, cylinders, heads, sectors, sector_size); + std::error_condition err; err = chd->write_metadata(HARD_DISK_METADATA_TAG, 0, metadata); if (err) report_error(1, "Error adding hard disk metadata: %s", err.message()); @@ -1990,9 +2124,7 @@ static void do_create_hd(parameters_map ¶ms) catch (...) { // delete the output file - auto output_chd_str = params.find(OPTION_OUTPUT); - if (output_chd_str != params.end()) - osd_file::remove(*output_chd_str->second); + osd_file::remove(*output_chd_str); throw; } } @@ -2018,21 +2150,21 @@ static void do_create_cd(parameters_map ¶ms) // process output CHD chd_file output_parent; - std::string *output_chd_str = parse_output_chd_parameters(params, output_parent); + const auto output_chd_str = parse_output_chd_parameters(params, output_parent); // process hunk size - uint32_t hunk_size = output_parent.opened() ? output_parent.hunk_bytes() : cdrom_file::FRAMES_PER_HUNK * cdrom_file::FRAME_SIZE; - parse_hunk_size(params, cdrom_file::FRAME_SIZE, hunk_size); + const uint32_t hunk_size = parse_hunk_size(params, output_parent, cdrom_file::FRAME_SIZE, cdrom_file::FRAMES_PER_HUNK * cdrom_file::FRAME_SIZE); + if (output_parent.opened() && (output_parent.unit_bytes() != cdrom_file::FRAME_SIZE)) + report_error(1, "Output parent CHD sector size %u bytes does not match CD-ROM frame size %u bytes", output_parent.unit_bytes(), cdrom_file::FRAME_SIZE); // process compression chd_codec_type compression[4]; - memcpy(compression, s_default_cd_compression, sizeof(compression)); - parse_compression(params, compression); + parse_compression(params, s_default_cd_compression, output_parent, compression); // process numprocessors parse_numprocessors(params); - // pad each track to a 4-frame boundary. cdrom.c will deal with this on the read side + // pad each track to a 4-frame boundary. cdrom.cpp will deal with this on the read side uint32_t origtotalsectors = 0; uint32_t totalsectors = 0; for (int tracknum = 0; tracknum < toc.numtrks; tracknum++) @@ -2045,45 +2177,34 @@ static void do_create_cd(parameters_map ¶ms) } // print some info - printf("Output CHD: %s\n", output_chd_str->c_str()); + util::stream_format(std::cout, "Output CHD: %s\n", *output_chd_str); 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()); - printf("Input tracks: %d\n", toc.numtrks); - printf("Input length: %s\n", msf_string_from_frames(origtotalsectors).c_str()); - printf("Compression: %s\n", compression_string(compression).c_str()); - printf("Logical size: %s\n", big_int_string(uint64_t(totalsectors) * cdrom_file::FRAME_SIZE).c_str()); + util::stream_format(std::cout, "Parent CHD: %s\n", *params.find(OPTION_OUTPUT_PARENT)->second); + util::stream_format(std::cout, "Input file: %s\n", *input_file_str->second); + util::stream_format(std::cout, "Input tracks: %d\n", toc.numtrks); + util::stream_format(std::cout, "Input length: %s\n", msf_string_from_frames(origtotalsectors)); + util::stream_format(std::cout, "Compression: %s\n", compression_string(compression)); + util::stream_format(std::cout, "Logical size: %s\n", big_int_string(uint64_t(totalsectors) * cdrom_file::FRAME_SIZE)); // catch errors so we can close & delete the output file - chd_cd_compressor *chd = nullptr; try { // create the new CD - chd = new chd_cd_compressor(toc, track_info); - std::error_condition err; - if (output_parent.opened()) - err = chd->create(output_chd_str->c_str(), uint64_t(totalsectors) * uint64_t(cdrom_file::FRAME_SIZE), hunk_size, compression, output_parent); - else - err = chd->create(output_chd_str->c_str(), uint64_t(totalsectors) * uint64_t(cdrom_file::FRAME_SIZE), hunk_size, cdrom_file::FRAME_SIZE, compression); - if (err) - report_error(1, "Error creating CHD file (%s): %s", *output_chd_str, err.message()); + auto chd = std::make_unique<chd_cd_compressor>(toc, track_info); + create_output_chd(*chd, *output_chd_str, uint64_t(totalsectors) * cdrom_file::FRAME_SIZE, hunk_size, cdrom_file::FRAME_SIZE, compression, output_parent); // add the standard CD metadata; we do this even if we have a parent because it might be different - err = cdrom_file::write_metadata(chd, toc); + const std::error_condition err = cdrom_file::write_metadata(chd.get(), toc); if (err) report_error(1, "Error adding CD metadata: %s", err.message()); // compress it generically compress_common(*chd); - delete chd; } catch (...) { - delete chd; // delete the output file - auto output_chd_str = params.find(OPTION_OUTPUT); - if (output_chd_str != params.end()) - osd_file::remove(*output_chd_str->second); + osd_file::remove(*output_chd_str); throw; } } @@ -2097,65 +2218,53 @@ static void do_create_cd(parameters_map ¶ms) static void do_create_dvd(parameters_map ¶ms) { // process input file - util::core_file::ptr input_file; - auto input_file_str = params.find(OPTION_INPUT); - if (input_file_str != params.end()) - { - std::error_condition const filerr = util::core_file::open(*input_file_str->second, OPEN_FLAG_READ, input_file); - if (filerr) - report_error(1, "Unable to open file (%s): %s", *input_file_str->second, filerr.message()); - } + auto [input_file, input_file_str] = open_input_file(params); // process output CHD chd_file output_parent; - std::string *output_chd_str = parse_output_chd_parameters(params, output_parent); + const auto output_chd_str = parse_output_chd_parameters(params, output_parent); + + // process hunk size + const uint32_t hunk_size = parse_hunk_size(params, output_parent, 2048, 2 * 2048); + if (output_parent.opened() && (output_parent.unit_bytes() != 2048)) + report_error(1, "Output parent CHD sector size %u bytes does not match DVD-ROM sector size 2048 bytes", output_parent.unit_bytes()); // process input start/end - uint64_t filesize = 0; - input_file->length(filesize); // FIXME: check error return + const auto [input_size, input_start, input_end] = parse_input_start_end(params, *input_file, hunk_size, hunk_size); + if ((input_end - input_start) % 2048) + report_error(1, "Data size %s is not divisible by sector size 2048", big_int_string(input_end - input_start)); // process compression chd_codec_type compression[4]; - memcpy(compression, s_default_hd_compression, sizeof(compression)); // No reason to be different than HD for compression - if (!input_file) - compression[0] = compression[1] = compression[2] = compression[3] = CHD_CODEC_NONE; - parse_compression(params, compression); + parse_compression(params, s_default_hd_compression, output_parent, compression); // No reason to be different than HD for compression // process numprocessors parse_numprocessors(params); - // validate the size - if (filesize % 2048 != 0) - report_error(1, "Data size is not divisible by 2048"); - - uint32_t totalsectors = filesize / 2048; - // print some info - printf("Output CHD: %s\n", output_chd_str->c_str()); + util::stream_format(std::cout, "Output CHD: %s\n", *output_chd_str); 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()); - printf("Compression: %s\n", compression_string(compression).c_str()); - printf("Logical size: %s\n", big_int_string(uint64_t(totalsectors) * 2048).c_str()); + util::stream_format(std::cout, "Parent CHD: %s\n", *params.find(OPTION_OUTPUT_PARENT)->second); + util::stream_format(std::cout, "Input file: %s\n", *input_file_str); + if (input_start != 0 || input_end != input_size) + { + util::stream_format(std::cout, "Input start: %s\n", big_int_string(input_start)); + util::stream_format(std::cout, "Input length: %s\n", big_int_string(input_end - input_start)); + } + util::stream_format(std::cout, "Compression: %s\n", compression_string(compression)); + util::stream_format(std::cout, "Logical size: %s\n", big_int_string(input_end - input_start)); // catch errors so we can close & delete the output file try { - // create the new dvd - std::unique_ptr<chd_file_compressor> chd; - chd.reset(new chd_rawfile_compressor(*input_file, 0, filesize)); - std::error_condition err; - if (output_parent.opened()) - err = chd->create(output_chd_str->c_str(), uint64_t(totalsectors) * 2048, 2048, compression, output_parent); - else - err = chd->create(output_chd_str->c_str(), uint64_t(totalsectors) * 2048, 2048, 2048, compression); - if (err) - report_error(1, "Error creating CHD file (%s): %s", output_chd_str, err.message()); + // create the new DVD + auto chd = std::make_unique<chd_rawfile_compressor>(*input_file, input_start, input_end); + create_output_chd(*chd, *output_chd_str, input_end - input_start, hunk_size, 2048, compression, output_parent); - // add the standard dvd type tag - err = chd->write_metadata(DVD_METADATA_TAG, 0, ""); + // add the standard DVD type tag + const std::error_condition err = chd->write_metadata(DVD_METADATA_TAG, 0, ""); if (err) - report_error(1, "Error adding dvd metadata: %s", err.message()); + report_error(1, "Error adding DVD metadata: %s", err.message()); // compress it generically compress_common(*chd); @@ -2163,9 +2272,7 @@ static void do_create_dvd(parameters_map ¶ms) catch (...) { // delete the output file - auto output_chd_str = params.find(OPTION_OUTPUT); - if (output_chd_str != params.end()) - osd_file::remove(*output_chd_str->second); + osd_file::remove(*output_chd_str); throw; } } @@ -2191,12 +2298,10 @@ static void do_create_ld(parameters_map ¶ms) // process output CHD chd_file output_parent; - std::string *output_chd_str = parse_output_chd_parameters(params, output_parent); + const auto output_chd_str = parse_output_chd_parameters(params, output_parent); // process input start/end - uint64_t input_start; - uint64_t input_end; - parse_input_start_end(params, aviinfo.video_numsamples, 0, 1, input_start, input_end); + auto [input_start, input_end] = parse_input_start_end(params, aviinfo.video_numsamples, 0, 1); // determine parameters of the incoming video stream avi_info info; @@ -2221,13 +2326,11 @@ static void do_create_ld(parameters_map ¶ms) info.bytes_per_frame = avhuff_encoder::raw_data_size(info.width, info.height, info.channels, info.max_samples_per_frame); // process hunk size - uint32_t hunk_size = output_parent.opened() ? output_parent.hunk_bytes() : info.bytes_per_frame; - parse_hunk_size(params, info.bytes_per_frame, hunk_size); + const uint32_t hunk_size = parse_hunk_size(params, output_parent, info.bytes_per_frame, info.bytes_per_frame); // process compression chd_codec_type compression[4]; - memcpy(compression, s_default_ld_compression, sizeof(compression)); - parse_compression(params, compression); + parse_compression(params, s_default_ld_compression, output_parent, compression); // disable support for uncompressed ones until the extraction code can handle it if (compression[0] == CHD_CODEC_NONE) report_error(1, "Uncompressed is not supported"); @@ -2236,39 +2339,33 @@ static void do_create_ld(parameters_map ¶ms) parse_numprocessors(params); // print some info - printf("Output CHD: %s\n", output_chd_str->c_str()); + util::stream_format(std::cout, "Output CHD: %s\n", *output_chd_str); 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()); + util::stream_format(std::cout, "Parent CHD: %s\n", *params.find(OPTION_OUTPUT_PARENT)->second); + util::stream_format(std::cout, "Input file: %s\n", *input_file_str->second); if (input_start != 0 && input_end != aviinfo.video_numsamples) - printf("Input start: %s\n", big_int_string(input_start).c_str()); - printf("Input length: %s (%02d:%02d:%02d)\n", big_int_string(input_end - input_start).c_str(), + util::stream_format(std::cout, "Input start: %s\n", big_int_string(input_start)); + util::stream_format(std::cout, "Input length: %s (%02d:%02d:%02d)\n", big_int_string(input_end - input_start), uint32_t((uint64_t(input_end - input_start) * 1000000 / info.fps_times_1million / 60 / 60)), uint32_t(((uint64_t(input_end - input_start) * 1000000 / info.fps_times_1million / 60) % 60)), uint32_t(((uint64_t(input_end - input_start) * 1000000 / info.fps_times_1million) % 60))); - printf("Frame rate: %d.%06d\n", info.fps_times_1million / 1000000, info.fps_times_1million % 1000000); - printf("Frame size: %d x %d %s\n", info.width, info.height * (info.interlaced ? 2 : 1), info.interlaced ? "interlaced" : "non-interlaced"); - printf("Audio: %d channels at %d Hz\n", info.channels, info.rate); - printf("Compression: %s\n", compression_string(compression).c_str()); - printf("Hunk size: %s\n", big_int_string(hunk_size).c_str()); - printf("Logical size: %s\n", big_int_string(uint64_t(input_end - input_start) * hunk_size).c_str()); + util::stream_format(std::cout, "Frame rate: %d.%06d\n", info.fps_times_1million / 1000000, info.fps_times_1million % 1000000); + util::stream_format(std::cout, "Frame size: %d x %d %s\n", info.width, info.height * (info.interlaced ? 2 : 1), info.interlaced ? "interlaced" : "non-interlaced"); + util::stream_format(std::cout, "Audio: %d channels at %d Hz\n", info.channels, info.rate); + util::stream_format(std::cout, "Compression: %s\n", compression_string(compression)); + util::stream_format(std::cout, "Hunk size: %s\n", big_int_string(hunk_size)); + util::stream_format(std::cout, "Logical size: %s\n", big_int_string(uint64_t(input_end - input_start) * hunk_size)); // catch errors so we can close & delete the output file - chd_avi_compressor *chd = nullptr; try { // create the new CHD - chd = new chd_avi_compressor(*input_file, info, input_start, input_end); - std::error_condition err; - if (output_parent.opened()) - err = chd->create(output_chd_str->c_str(), uint64_t(input_end - input_start) * hunk_size, hunk_size, compression, output_parent); - else - err = chd->create(output_chd_str->c_str(), uint64_t(input_end - input_start) * hunk_size, hunk_size, info.bytes_per_frame, compression); - if (err) - report_error(1, "Error creating CHD file (%s): %s", *output_chd_str, err.message()); + auto chd = std::make_unique<chd_avi_compressor>(*input_file, info, input_start, input_end); + create_output_chd(*chd, *output_chd_str, uint64_t(input_end - input_start) * hunk_size, hunk_size, info.bytes_per_frame, compression, output_parent); // write the core A/V metadata std::string metadata = string_format(AV_METADATA_FORMAT, info.fps_times_1million / 1000000, info.fps_times_1million % 1000000, info.width, info.height, info.interlaced, info.channels, info.rate); + std::error_condition err; err = chd->write_metadata(AV_METADATA_TAG, 0, metadata); if (err) report_error(1, "Error adding AV metadata: %s\n", err.message()); @@ -2283,21 +2380,50 @@ static void do_create_ld(parameters_map ¶ms) if (err) report_error(1, "Error adding AVLD metadata: %s\n", err.message()); } - delete chd; } catch (...) { - delete chd; // delete the output file - auto output_chd_str = params.find(OPTION_OUTPUT); - if (output_chd_str != params.end()) - osd_file::remove(*output_chd_str->second); + osd_file::remove(*output_chd_str); throw; } } //------------------------------------------------- +// get_compression_defaults - use CHD metadata to +// pick the preferred type +//------------------------------------------------- + +static const std::array<chd_codec_type, 4> &get_compression_defaults(chd_file &input_chd) +{ + std::error_condition err = input_chd.check_is_hd(); + if (err == chd_file::error::METADATA_NOT_FOUND) + err = input_chd.check_is_dvd(); + if (!err) + return s_default_hd_compression; + if (err != chd_file::error::METADATA_NOT_FOUND) + throw err; + + err = input_chd.check_is_av(); + if (!err) + return s_default_ld_compression; + if (err != chd_file::error::METADATA_NOT_FOUND) + throw err; + + err = input_chd.check_is_cd(); + if (err == chd_file::error::METADATA_NOT_FOUND) + err = input_chd.check_is_gd(); + if (!err) + return s_default_cd_compression; + if (err != chd_file::error::METADATA_NOT_FOUND) + throw err; + + return s_default_raw_compression; +} + + +//------------------------------------------------- // do_copy - create a new CHD with data from // another CHD //------------------------------------------------- @@ -2310,71 +2436,49 @@ static void do_copy(parameters_map ¶ms) parse_input_chd_parameters(params, input_chd, input_parent_chd); // parse out input start/end - uint64_t input_start; - uint64_t input_end; - parse_input_start_end(params, input_chd.logical_bytes(), input_chd.hunk_bytes(), input_chd.hunk_bytes(), input_start, input_end); + const auto [input_start, input_end] = parse_input_start_end(params, input_chd.logical_bytes(), input_chd.hunk_bytes(), input_chd.hunk_bytes()); + // TODO: should we check that the input range is aligned to the unit size? // process output CHD chd_file output_parent; - std::string *output_chd_str = parse_output_chd_parameters(params, output_parent); + const auto output_chd_str = parse_output_chd_parameters(params, output_parent); // process hunk size - uint32_t hunk_size = input_chd.hunk_bytes(); - parse_hunk_size(params, 1, hunk_size); - if (hunk_size % input_chd.hunk_bytes() != 0 && input_chd.hunk_bytes() % hunk_size != 0) - report_error(1, "Hunk size is not an even multiple or divisor of input hunk size"); + const uint32_t hunk_size = parse_hunk_size(params, output_parent, input_chd.unit_bytes(), input_chd.hunk_bytes()); + if ((hunk_size % input_chd.hunk_bytes()) && (input_chd.hunk_bytes() % hunk_size)) // TODO: is this check still necessary, or is the unit size check enough? + report_error(1, "Hunk size is not a whole multiple or factor of input hunk size"); // process compression; we default to our current preferences using metadata to pick the type chd_codec_type compression[4]; - { - std::vector<uint8_t> metadata; - if (!input_chd.read_metadata(HARD_DISK_METADATA_TAG, 0, metadata)) - memcpy(compression, s_default_hd_compression, sizeof(compression)); - else if (!input_chd.read_metadata(AV_METADATA_TAG, 0, metadata)) - memcpy(compression, s_default_ld_compression, sizeof(compression)); - else if (!input_chd.read_metadata(CDROM_OLD_METADATA_TAG, 0, metadata) || - !input_chd.read_metadata(CDROM_TRACK_METADATA_TAG, 0, metadata) || - !input_chd.read_metadata(CDROM_TRACK_METADATA2_TAG, 0, metadata) || - !input_chd.read_metadata(GDROM_OLD_METADATA_TAG, 0, metadata) || - !input_chd.read_metadata(GDROM_TRACK_METADATA_TAG, 0, metadata)) - memcpy(compression, s_default_cd_compression, sizeof(compression)); - else - memcpy(compression, s_default_raw_compression, sizeof(compression)); - } - parse_compression(params, compression); + parse_compression(params, get_compression_defaults(input_chd), output_parent, compression); // process numprocessors parse_numprocessors(params); // print some info - printf("Output CHD: %s\n", output_chd_str->c_str()); + util::stream_format(std::cout, "Output CHD: %s\n", *output_chd_str); if (output_parent.opened()) - printf("Parent CHD: %s\n", params.find(OPTION_OUTPUT_PARENT)->second->c_str()); - printf("Input CHD: %s\n", params.find(OPTION_INPUT)->second->c_str()); + util::stream_format(std::cout, "Parent CHD: %s\n", *params.find(OPTION_OUTPUT_PARENT)->second); + util::stream_format(std::cout, "Input CHD: %s\n", *params.find(OPTION_INPUT)->second); if (input_start != 0 || input_end != input_chd.logical_bytes()) { - printf("Input start: %s\n", big_int_string(input_start).c_str()); - printf("Input length: %s\n", big_int_string(input_end - input_start).c_str()); + util::stream_format(std::cout, "Input start: %s\n", big_int_string(input_start)); + util::stream_format(std::cout, "Input length: %s\n", big_int_string(input_end - input_start)); } - printf("Compression: %s\n", compression_string(compression).c_str()); - printf("Hunk size: %s\n", big_int_string(hunk_size).c_str()); - printf("Logical size: %s\n", big_int_string(input_end - input_start).c_str()); + util::stream_format(std::cout, "Compression: %s\n", compression_string(compression)); + util::stream_format(std::cout, "Hunk size: %s\n", big_int_string(hunk_size)); + util::stream_format(std::cout, "Logical size: %s\n", big_int_string(input_end - input_start)); // catch errors so we can close & delete the output file - chd_chdfile_compressor *chd = nullptr; try { // create the new CHD - chd = new chd_chdfile_compressor(input_chd, input_start, input_end); - std::error_condition err; - if (output_parent.opened()) - err = chd->create(output_chd_str->c_str(), input_end - input_start, hunk_size, compression, output_parent); - else - err = chd->create(output_chd_str->c_str(), input_end - input_start, hunk_size, input_chd.unit_bytes(), compression); - if (err) - report_error(1, "Error creating CHD file (%s): %s", *output_chd_str, err.message()); + std::unique_ptr<cdrom_file> cdrom; // want this to be unwound after chd + auto chd = std::make_unique<chd_chdfile_compressor>(input_chd, input_start, input_end); + create_output_chd(*chd, *output_chd_str, input_end - input_start, hunk_size, input_chd.unit_bytes(), compression, output_parent); // clone all the metadata, upgrading where appropriate + std::error_condition err; std::vector<uint8_t> metadata; chd_metadata_tag metatag; uint8_t metaflags; @@ -2405,9 +2509,9 @@ static void do_copy(parameters_map ¶ms) // if we need to re-do the CD metadata, do it now if (redo_cd) { - cdrom_file *cdrom = new cdrom_file(&input_chd); + cdrom = std::make_unique<cdrom_file>(&input_chd); const cdrom_file::toc &toc = cdrom->get_toc(); - err = cdrom_file::write_metadata(chd, toc); + err = cdrom_file::write_metadata(chd.get(), toc); if (err) report_error(1, "Error writing upgraded CD metadata: %s", err.message()); if (cdda_swap) @@ -2416,15 +2520,11 @@ static void do_copy(parameters_map ¶ms) // compress it generically compress_common(*chd); - delete chd; } catch (...) { - delete chd; // delete the output file - auto output_chd_str = params.find(OPTION_OUTPUT); - if (output_chd_str != params.end()) - osd_file::remove(*output_chd_str->second); + osd_file::remove(*output_chd_str); throw; } } @@ -2443,22 +2543,20 @@ static void do_extract_raw(parameters_map ¶ms) parse_input_chd_parameters(params, input_chd, input_parent_chd); // parse out input start/end - uint64_t input_start; - uint64_t input_end; - parse_input_start_end(params, input_chd.logical_bytes(), input_chd.hunk_bytes(), input_chd.hunk_bytes(), input_start, input_end); + const auto [input_start, input_end] = parse_input_start_end(params, input_chd.logical_bytes(), input_chd.hunk_bytes(), input_chd.hunk_bytes()); // verify output file doesn't exist auto output_file_str = params.find(OPTION_OUTPUT); if (output_file_str != params.end()) - check_existing_output_file(params, output_file_str->second->c_str()); + check_existing_output_file(params, *output_file_str->second); // print some info - printf("Output File: %s\n", output_file_str->second->c_str()); - printf("Input CHD: %s\n", params.find(OPTION_INPUT)->second->c_str()); + util::stream_format(std::cout, "Output File: %s\n", *output_file_str->second); + util::stream_format(std::cout, "Input CHD: %s\n", *params.find(OPTION_INPUT)->second); if (input_start != 0 || input_end != input_chd.logical_bytes()) { - printf("Input start: %s\n", big_int_string(input_start).c_str()); - printf("Input length: %s\n", big_int_string(input_end - input_start).c_str()); + util::stream_format(std::cout, "Input start: %s\n", big_int_string(input_start)); + util::stream_format(std::cout, "Input length: %s\n", big_int_string(input_end - input_start)); } // catch errors so we can close & delete the output file @@ -2483,9 +2581,8 @@ static void do_extract_raw(parameters_map ¶ms) report_error(1, "Error reading CHD file (%s): %s", *params.find(OPTION_INPUT)->second, err.message()); // write to the output - size_t count; - std::error_condition const writerr = output_file->write(&buffer[0], bytes_to_read, count); - if (writerr || (count != bytes_to_read)) + auto const [writerr, count] = write(*output_file, &buffer[0], bytes_to_read); + if (writerr) report_error(1, "Error writing to file; check disk space (%s)", *output_file_str->second); // advance @@ -2494,7 +2591,7 @@ static void do_extract_raw(parameters_map ¶ms) // finish up output_file.reset(); - printf("Extraction complete \n"); + util::stream_format(std::cout, "Extraction complete \n"); } catch (...) { @@ -2528,63 +2625,160 @@ static void do_extract_cd(parameters_map ¶ms) // verify output file doesn't exist auto output_file_str = params.find(OPTION_OUTPUT); if (output_file_str != params.end()) - check_existing_output_file(params, output_file_str->second->c_str()); + check_existing_output_file(params, *output_file_str->second); - // verify output BIN file doesn't exist + // determine output type based on the specified file extension + int mode = MODE_NORMAL; + if (core_filename_ends_with(*output_file_str->second, ".cue")) + mode = MODE_CUEBIN; + else if (core_filename_ends_with(*output_file_str->second, ".gdi")) + mode = MODE_GDI; + + // determine the output bin filename based on provided input parameters auto output_bin_file_fnd = params.find(OPTION_OUTPUT_BIN); std::string default_name(*output_file_str->second); + + // split path and extension int chop = default_name.find_last_of('.'); - if (chop != -1) + if (chop != std::string::npos) default_name.erase(chop, default_name.size()); - std::string basename = default_name; - default_name.append(".bin"); + + // GDIs will always output as split bin + bool is_splitbin = mode == MODE_GDI || params.find(OPTION_OUTPUT_SPLITBIN) != params.end(); + if (!is_splitbin && cdrom->is_gdrom() && mode == MODE_CUEBIN) + { + // GD-ROM cue/bin is in Redump format which should always be split by tracks + util::stream_format(std::cout, "Warning: --%s is required for this specific combination of input disc type and output format, enabling automatically\n", OPTION_OUTPUT_SPLITBIN); + is_splitbin = true; + } + + if (is_splitbin) + { + if (mode == MODE_GDI) + { + default_name += "%02t"; + } + else + { + const std::string format = toc.numtrks >= 10 ? "%02t" : "%t"; + default_name += " (Track " + format + ")"; + } + } + + std::string output_bin_file_ext = ".bin"; std::string *output_bin_file_str; if (output_bin_file_fnd == params.end()) + { output_bin_file_str = &default_name; + } else + { output_bin_file_str = output_bin_file_fnd->second; - check_existing_output_file(params, output_bin_file_str->c_str()); + chop = output_bin_file_str->find_last_of('.'); + if (chop != std::string::npos) + { + output_bin_file_ext = output_bin_file_str->substr(chop, output_bin_file_str->size() - chop); + output_bin_file_str->erase(chop, output_bin_file_str->size()); + } + } + + if (output_bin_file_str->find('"') != std::string::npos || output_bin_file_ext.find('"') != std::string::npos) + report_error(1, "Output bin filename (%s%s) must not contain quotation marks", *output_bin_file_str, output_bin_file_ext); // print some info - printf("Output TOC: %s\n", output_file_str->second->c_str()); - printf("Output Data: %s\n", output_bin_file_str->c_str()); - printf("Input CHD: %s\n", params.find(OPTION_INPUT)->second->c_str()); + util::stream_format(std::cout, "Input CHD: %s\n", *params.find(OPTION_INPUT)->second); + util::stream_format(std::cout, "Output TOC: %s\n", *output_file_str->second); // catch errors so we can close & delete the output file + std::vector<std::string> track_filenames; util::core_file::ptr output_bin_file; util::core_file::ptr output_toc_file; + std::vector<std::string> output_bin_filenames; + std::string trackbin_name; try { - int mode = MODE_NORMAL; - - if (output_file_str->second->find(".cue") != -1) - { - mode = MODE_CUEBIN; - } - else if (output_file_str->second->find(".gdi") != -1) - { - mode = MODE_GDI; - } - // process output file std::error_condition filerr = util::core_file::open(*output_file_str->second, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_NO_BOM, output_toc_file); if (filerr) report_error(1, "Unable to open file (%s): %s", *output_file_str->second, filerr.message()); - // process output BIN file - if (mode != MODE_GDI) - { - filerr = util::core_file::open(*output_bin_file_str, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, output_bin_file); - if (filerr) - report_error(1, "Unable to open file (%s): %s", *output_bin_file_str, filerr.message()); - } - - // determine total frames uint64_t total_bytes = 0; for (int tracknum = 0; tracknum < toc.numtrks; tracknum++) + { + // determine total frames total_bytes += toc.tracks[tracknum].frames * (toc.tracks[tracknum].datasize + toc.tracks[tracknum].subsize); + // generate output filename for each track + std::string new_trackbin_name = *output_bin_file_str; + + if (mode == MODE_GDI && toc.tracks[tracknum].trktype == cdrom_file::CD_TRACK_AUDIO) + new_trackbin_name += ".raw"; + else + new_trackbin_name += output_bin_file_ext; + + // variable replacement in output filename + const std::regex variables_regex("(%*)(%([+-]?\\d+)?([a-zA-Z]))"); + std::string::const_iterator new_trackbin_name_itr = new_trackbin_name.begin(); + std::string::const_iterator new_trackbin_name_end = new_trackbin_name.end(); + std::string filename_formatted = new_trackbin_name; + std::smatch variable_matches; + bool found_track_variable = false; + + while (std::regex_search(new_trackbin_name_itr, new_trackbin_name_end, variable_matches, variables_regex)) + { + // full_match will always have one leading %, so if leading_escape has an even number of %s then + // we can know that we're working on an unescaped % + const std::string leading_escape = variable_matches[1].str(); + const std::string full_match = variable_matches[2].str(); + const std::string format_part = variable_matches[3].str(); + const std::string format_type = variable_matches[4].str(); + + if ((leading_escape.size() % 2) == 0) + { + std::string replacement; + + if (format_type == "t") + { + // track number + if (is_splitbin) + { + replacement = util::string_format("%" + format_part + "d", tracknum+1); + found_track_variable = true; + } + } + else + { + util::stream_format(std::cout, "Warning: encountered unknown format value '%s', ignoring\n", format_type); + } + + if (!replacement.empty()) + { + // replace all instances of encountered full format token + size_t index = std::string::npos; + while ((index = filename_formatted.find(full_match)) != std::string::npos) + filename_formatted.replace(index, full_match.size(), replacement); + } + } + + new_trackbin_name_itr = variable_matches.suffix().first; // move past match for next loop + } + + if (is_splitbin && !found_track_variable) + { + report_error(1, "A track number variable (%%t) must be specified in the output bin filename when --%s is enabled\n", OPTION_OUTPUT_SPLITBIN); + } + + // verify output BIN file doesn't exist + check_existing_output_file(params, filename_formatted); + + // display all new filenames to the user + if (track_filenames.empty() || filename_formatted != track_filenames.back()) + util::stream_format(std::cout, "Output Data: %s\n", filename_formatted); + + track_filenames.push_back(filename_formatted); + } + // GDI must start with the # of tracks if (mode == MODE_GDI) { @@ -2627,49 +2821,118 @@ static void do_extract_cd(parameters_map ¶ms) output_toc_file->printf("CD_ROM\n\n\n"); } + if (cdrom->is_gdrom() && mode == MODE_CUEBIN) + { + // modify TOC to match Redump cue/bin format as best as possible + cdrom_file::toc *trackinfo = (cdrom_file::toc*)&toc; + + // TOSEC GDI-based CHDs have the padframes field set to non-0 where the pregaps for the next track would be + const bool has_physical_pregap = trackinfo->tracks[0].padframes == 0; + + for (int tracknum = 1; tracknum < toc.numtrks; tracknum++) + { + // pgdatasize should never be set in GD-ROMs currently, so if it is set then assume the TOC has proper pregap values + if (trackinfo->tracks[tracknum].pgdatasize != 0) + break; + + // don't adjust the first track of the single-density and high-density areas + if (toc.tracks[tracknum].physframeofs == 45000) + continue; + + if (!has_physical_pregap) + { + // NOTE: This will generate a cue with PREGAP commands instead of INDEX 00 because the pregap data isn't baked into the bins + trackinfo->tracks[tracknum].pregap += trackinfo->tracks[tracknum-1].padframes; + + // "type 1" (only one data track in high-density area) and "type 2" (1 data and then the rest of the tracks being audio tracks in high-density area) don't require any adjustments + if (tracknum + 1 >= toc.numtrks && toc.tracks[tracknum].trktype != cdrom_file::CD_TRACK_AUDIO) + { + if (toc.tracks[tracknum-1].trktype != cdrom_file::CD_TRACK_AUDIO) + { + // "type 3" where the high-density area is just two data tracks + // there shouldn't be any pregap in the padframes from the previous track in this case, and the full 3s pregap is baked into the previous track + // Only known to be used by Shenmue II JP's discs 2, 3, 4 and Virtua Fighter History & VF4 + trackinfo->tracks[tracknum-1].padframes += 225; + + trackinfo->tracks[tracknum].pregap += 225; + trackinfo->tracks[tracknum].splitframes = 225; + trackinfo->tracks[tracknum].pgdatasize = trackinfo->tracks[tracknum].datasize; + trackinfo->tracks[tracknum].pgtype = trackinfo->tracks[tracknum].trktype; + } + else + { + // "type 3 split" where the first track and last of the high-density area are data tracks and in between is audio tracks + // TODO: These 75 frames are actually included at the end of the previous track so should be written + // It's currently not possible to format it as expected without hacky code because the 150 pregap for the last track + // is sandwiched between these 75 frames and the actual track data. + // The 75 frames seems to normally be 0s so this should be ok for now until a use case is found. + trackinfo->tracks[tracknum-1].frames -= 75; + trackinfo->tracks[tracknum].pregap += 75; + } + } + } + else + { + int curextra = 150; // 00:02:00 + if (tracknum + 1 >= toc.numtrks && toc.tracks[tracknum].trktype != cdrom_file::CD_TRACK_AUDIO) + curextra += 75; // 00:01:00, special case when last track is data + + trackinfo->tracks[tracknum-1].padframes = curextra; + + trackinfo->tracks[tracknum].pregap += curextra; + trackinfo->tracks[tracknum].splitframes = curextra; + trackinfo->tracks[tracknum].pgdatasize = trackinfo->tracks[tracknum].datasize; + trackinfo->tracks[tracknum].pgtype = trackinfo->tracks[tracknum].trktype; + } + } + } + // iterate over tracks and copy all data + uint64_t totaloutputoffs = 0; uint64_t outputoffs = 0; uint32_t discoffs = 0; std::vector<uint8_t> buffer; + for (int tracknum = 0; tracknum < toc.numtrks; tracknum++) { - std::string trackbin_name = basename; - - if (mode == MODE_GDI) + if (track_filenames[tracknum] != trackbin_name) { - trackbin_name += util::string_format("%02d", tracknum+1); - if (toc.tracks[tracknum].trktype == cdrom_file::CD_TRACK_AUDIO) - trackbin_name += ".raw"; - else - trackbin_name += ".bin"; + totaloutputoffs += outputoffs; + outputoffs = 0; + + if (mode != MODE_GDI) + discoffs = 0; output_bin_file.reset(); + trackbin_name = track_filenames[tracknum]; + filerr = util::core_file::open(trackbin_name, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, output_bin_file); if (filerr) report_error(1, "Unable to open file (%s): %s", trackbin_name, filerr.message()); - outputoffs = 0; + output_bin_filenames.push_back(trackbin_name); } - // output the metadata about the track to the TOC file - const cdrom_file::track_info &trackinfo = toc.tracks[tracknum]; - if (mode == MODE_GDI) + if (cdrom->is_gdrom() && mode == MODE_CUEBIN) { - output_track_metadata(mode, *output_toc_file, tracknum, trackinfo, std::string(core_filename_extract_base(trackbin_name)), discoffs, outputoffs); - } - else - { - output_track_metadata(mode, *output_toc_file, tracknum, trackinfo, std::string(core_filename_extract_base(*output_bin_file_str)), discoffs, outputoffs); + if (tracknum == 0) + output_toc_file->printf("REM SINGLE-DENSITY AREA\n"); + else if (toc.tracks[tracknum].physframeofs == 45000) + output_toc_file->printf("REM HIGH-DENSITY AREA\n"); } + // output the metadata about the track to the TOC file + const cdrom_file::track_info &trackinfo = toc.tracks[tracknum]; + output_track_metadata(mode, *output_toc_file, tracknum, trackinfo, std::string(core_filename_extract_base(trackbin_name)), discoffs, outputoffs); + // If this is bin/cue output and the CHD contains subdata, warn the user and don't include // the subdata size in the buffer calculation. uint32_t output_frame_size = trackinfo.datasize + ((trackinfo.subtype != cdrom_file::CD_SUB_NONE) ? trackinfo.subsize : 0); if (trackinfo.subtype != cdrom_file::CD_SUB_NONE && ((mode == MODE_CUEBIN) || (mode == MODE_GDI))) { - printf("Warning: Track %d has subcode data. bin/cue and gdi formats cannot contain subcode data and it will be omitted.\n", tracknum+1); - printf(" : This may affect usage of the output image. Use bin/toc output to keep all data.\n"); + util::stream_format(std::cout, "Warning: Track %d has subcode data. bin/cue and gdi formats cannot contain subcode data and it will be omitted.\n", tracknum+1); + util::stream_format(std::cout, " : This may affect usage of the output image. Use bin/toc output to keep all data.\n"); output_frame_size = trackinfo.datasize; } @@ -2678,40 +2941,52 @@ static void do_extract_cd(parameters_map ¶ms) // now read and output the actual data uint32_t bufferoffs = 0; - uint32_t actualframes = trackinfo.frames - trackinfo.padframes; + uint32_t actualframes = trackinfo.frames - trackinfo.padframes + trackinfo.splitframes; for (uint32_t frame = 0; frame < actualframes; frame++) { - progress(false, "Extracting, %.1f%% complete... \r", 100.0 * double(outputoffs) / double(total_bytes)); + progress(false, "Extracting, %.1f%% complete... \r", 100.0 * double(totaloutputoffs + outputoffs) / double(total_bytes)); + + int trk, frameofs; + if (tracknum > 0 && frame < trackinfo.splitframes) + { + // pull data from previous track, the reverse of how splitframes is used when making the GD-ROM CHDs + trk = tracknum - 1; + frameofs = toc.tracks[trk].frames - trackinfo.splitframes + frame; + } + else + { + trk = tracknum; + frameofs = frame - trackinfo.splitframes; + } // read the data - cdrom->read_data(cdrom->get_track_start_phys(tracknum) + frame, &buffer[bufferoffs], trackinfo.trktype, true); + cdrom->read_data(cdrom->get_track_start_phys(trk) + frameofs, &buffer[bufferoffs], toc.tracks[trk].trktype, true); // for CDRWin and GDI audio tracks must be reversed // in the case of GDI and CHD version < 5 we assuming source CHD image is GDROM so audio tracks is already reversed - if (((mode == MODE_GDI && input_chd.version() > 4) || (mode == MODE_CUEBIN)) && (trackinfo.trktype == cdrom_file::CD_TRACK_AUDIO)) - for (int swapindex = 0; swapindex < trackinfo.datasize; swapindex += 2) + if (((mode == MODE_GDI && input_chd.version() > 4) || (mode == MODE_CUEBIN)) && (toc.tracks[trk].trktype == cdrom_file::CD_TRACK_AUDIO)) + for (int swapindex = 0; swapindex < toc.tracks[trk].datasize; swapindex += 2) { uint8_t swaptemp = buffer[bufferoffs + swapindex]; buffer[bufferoffs + swapindex] = buffer[bufferoffs + swapindex + 1]; buffer[bufferoffs + swapindex + 1] = swaptemp; } - bufferoffs += trackinfo.datasize; + bufferoffs += toc.tracks[trk].datasize; discoffs++; // read the subcode data - if (trackinfo.subtype != cdrom_file::CD_SUB_NONE && (mode == MODE_NORMAL)) + if (toc.tracks[trk].subtype != cdrom_file::CD_SUB_NONE && (mode == MODE_NORMAL)) { - cdrom->read_subcode(cdrom->get_track_start_phys(tracknum) + frame, &buffer[bufferoffs], true); - bufferoffs += trackinfo.subsize; + cdrom->read_subcode(cdrom->get_track_start_phys(trk) + frameofs, &buffer[bufferoffs], true); + bufferoffs += toc.tracks[trk].subsize; } // write it out if we need to if (bufferoffs == buffer.size() || frame == actualframes - 1) { output_bin_file->seek(outputoffs, SEEK_SET); - size_t byteswritten; - std::error_condition const writerr = output_bin_file->write(&buffer[0], bufferoffs, byteswritten); - if (writerr || (byteswritten != bufferoffs)) + auto const [writerr, byteswritten] = write(*output_bin_file, &buffer[0], bufferoffs); + if (writerr) report_error(1, "Error writing frame %d to file (%s): %s\n", frame, *output_file_str->second, "Write error"); outputoffs += bufferoffs; bufferoffs = 0; @@ -2724,99 +2999,21 @@ static void do_extract_cd(parameters_map ¶ms) // finish up output_bin_file.reset(); output_toc_file.reset(); - printf("Extraction complete \n"); + util::stream_format(std::cout, "Extraction complete \n"); } catch (...) { // delete the output files output_bin_file.reset(); output_toc_file.reset(); - osd_file::remove(*output_bin_file_str); + for (auto const &output_bin_filename : output_bin_filenames) + osd_file::remove(output_bin_filename); osd_file::remove(*output_file_str->second); throw; } } -//------------------------------------------------- -// do_extract_dvd - extract a DVD image from a -// CHD image, currently identical to extractraw -//------------------------------------------------- - -static void do_extract_dvd(parameters_map ¶ms) -{ - // parse out input files - chd_file input_parent_chd; - chd_file input_chd; - parse_input_chd_parameters(params, input_chd, input_parent_chd); - - // parse out input start/end - uint64_t input_start; - uint64_t input_end; - parse_input_start_end(params, input_chd.logical_bytes(), input_chd.hunk_bytes(), input_chd.hunk_bytes(), input_start, input_end); - - // verify output file doesn't exist - auto output_file_str = params.find(OPTION_OUTPUT); - if (output_file_str != params.end()) - check_existing_output_file(params, output_file_str->second->c_str()); - - // print some info - printf("Output File: %s\n", output_file_str->second->c_str()); - printf("Input CHD: %s\n", params.find(OPTION_INPUT)->second->c_str()); - if (input_start != 0 || input_end != input_chd.logical_bytes()) - { - printf("Input start: %s\n", big_int_string(input_start).c_str()); - printf("Input length: %s\n", big_int_string(input_end - input_start).c_str()); - } - - // catch errors so we can close & delete the output file - util::core_file::ptr output_file; - try - { - // process output file - std::error_condition const filerr = util::core_file::open(*output_file_str->second, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, output_file); - if (filerr) - report_error(1, "Unable to open file (%s): %s", *output_file_str->second, filerr.message()); - - // copy all data - std::vector<uint8_t> buffer((TEMP_BUFFER_SIZE / input_chd.hunk_bytes()) * input_chd.hunk_bytes()); - for (uint64_t offset = input_start; offset < input_end; ) - { - progress(false, "Extracting, %.1f%% complete... \r", 100.0 * double(offset - input_start) / double(input_end - input_start)); - - // determine how much to read - uint32_t bytes_to_read = (std::min<uint64_t>)(buffer.size(), input_end - offset); - std::error_condition err = input_chd.read_bytes(offset, &buffer[0], bytes_to_read); - if (err) - report_error(1, "Error reading CHD file (%s): %s", *params.find(OPTION_INPUT)->second, err.message()); - - // write to the output - size_t count; - std::error_condition const writerr = output_file->write(&buffer[0], bytes_to_read, count); - if (writerr || (count != bytes_to_read)) - report_error(1, "Error writing to file; check disk space (%s)", *output_file_str->second); - - // advance - offset += bytes_to_read; - } - - // finish up - output_file.reset(); - printf("Extraction complete \n"); - } - catch (...) - { - // delete the output file - if (output_file != nullptr) - { - output_file.reset(); - osd_file::remove(*output_file_str->second); - } - throw; - } -} - - //------------------------------------------------- @@ -2862,9 +3059,7 @@ static void do_extract_ld(parameters_map ¶ms) report_error(1, "Frame size does not match hunk size for this CHD"); // parse out input start/end - uint64_t input_start; - uint64_t input_end; - parse_input_start_end(params, input_chd.hunk_count() / interlace_factor, 0, 1, input_start, input_end); + auto [input_start, input_end] = parse_input_start_end(params, input_chd.hunk_count() / interlace_factor, 0, 1); input_start *= interlace_factor; input_end *= interlace_factor; @@ -2886,15 +3081,15 @@ static void do_extract_ld(parameters_map ¶ms) // verify output file doesn't exist auto output_file_str = params.find(OPTION_OUTPUT); if (output_file_str != params.end()) - check_existing_output_file(params, output_file_str->second->c_str()); + check_existing_output_file(params, *output_file_str->second); // print some info - printf("Output File: %s\n", output_file_str->second->c_str()); - printf("Input CHD: %s\n", params.find(OPTION_INPUT)->second->c_str()); + util::stream_format(std::cout, "Output File: %s\n", *output_file_str->second); + util::stream_format(std::cout, "Input CHD: %s\n", *params.find(OPTION_INPUT)->second); if (input_start != 0 || input_end != input_chd.hunk_count()) { - printf("Input start: %s\n", big_int_string(input_start).c_str()); - printf("Input length: %s\n", big_int_string(input_end - input_start).c_str()); + util::stream_format(std::cout, "Input start: %s\n", big_int_string(input_start)); + util::stream_format(std::cout, "Input length: %s\n", big_int_string(input_end - input_start)); } // catch errors so we can close & delete the output file @@ -2931,7 +3126,7 @@ static void do_extract_ld(parameters_map ¶ms) input_chd.codec_configure(CHD_CODEC_AVHUFF, AVHUFF_CODEC_DECOMPRESS_CONFIG, &avconfig); // read the hunk into the buffers - std::error_condition err = input_chd.read_hunk(framenum, nullptr); + std::error_condition err = input_chd.codec_process_hunk(framenum); if (err) { uint64_t filepos = ~uint64_t(0); @@ -2958,7 +3153,7 @@ static void do_extract_ld(parameters_map ¶ms) // close and return output_file.reset(); - printf("Extraction complete \n"); + util::stream_format(std::cout, "Extraction complete \n"); } catch (...) { @@ -3029,13 +3224,13 @@ static void do_add_metadata(parameters_map ¶ms) flags &= ~CHD_MDFLAGS_CHECKSUM; // print some info - printf("Input file: %s\n", params.find(OPTION_INPUT)->second->c_str()); - printf("Tag: %c%c%c%c\n", (tag >> 24) & 0xff, (tag >> 16) & 0xff, (tag >> 8) & 0xff, tag & 0xff); - printf("Index: %d\n", index); + util::stream_format(std::cout, "Input file: %s\n", *params.find(OPTION_INPUT)->second); + util::stream_format(std::cout, "Tag: %c%c%c%c\n", (tag >> 24) & 0xff, (tag >> 16) & 0xff, (tag >> 8) & 0xff, tag & 0xff); + util::stream_format(std::cout, "Index: %d\n", index); if (text_str != params.end()) - printf("Text: %s\n", text.c_str()); + util::stream_format(std::cout, "Text: %s\n", text); else - printf("Data: %s (%d bytes)\n", file_str->second->c_str(), int(file.size())); + util::stream_format(std::cout, "Data: %s (%d bytes)\n", *file_str->second, file.size()); // write the metadata std::error_condition err; @@ -3046,7 +3241,7 @@ static void do_add_metadata(parameters_map ¶ms) if (err) report_error(1, "Error adding metadata: %s", err.message()); else - printf("Metadata added\n"); + util::stream_format(std::cout, "Metadata added\n"); } @@ -3077,16 +3272,16 @@ static void do_del_metadata(parameters_map ¶ms) index = atoi(index_str->second->c_str()); // print some info - printf("Input file: %s\n", params.find(OPTION_INPUT)->second->c_str()); - printf("Tag: %c%c%c%c\n", (tag >> 24) & 0xff, (tag >> 16) & 0xff, (tag >> 8) & 0xff, tag & 0xff); - printf("Index: %d\n", index); + util::stream_format(std::cout, "Input file: %s\n", *params.find(OPTION_INPUT)->second); + util::stream_format(std::cout, "Tag: %c%c%c%c\n", (tag >> 24) & 0xff, (tag >> 16) & 0xff, (tag >> 8) & 0xff, tag & 0xff); + util::stream_format(std::cout, "Index: %d\n", index); // write the metadata std::error_condition err = input_chd.delete_metadata(tag, index); if (err) report_error(1, "Error removing metadata: %s", err.message()); else - printf("Metadata removed\n"); + util::stream_format(std::cout, "Metadata removed\n"); } @@ -3104,7 +3299,7 @@ static void do_dump_metadata(parameters_map ¶ms) // verify output file doesn't exist auto output_file_str = params.find(OPTION_OUTPUT); if (output_file_str != params.end()) - check_existing_output_file(params, output_file_str->second->c_str()); + check_existing_output_file(params, *output_file_str->second); // process tag chd_metadata_tag tag = CHD_MAKE_TAG('?','?','?','?'); @@ -3142,15 +3337,15 @@ static void do_dump_metadata(parameters_map ¶ms) // output the metadata size_t count; - filerr = output_file->write(&buffer[0], buffer.size(), count); + std::tie(filerr, count) = write(*output_file, &buffer[0], buffer.size()); if (!filerr) filerr = output_file->flush(); - if (filerr || (count != buffer.size())) + if (filerr) report_error(1, "Error writing file (%s)", *output_file_str->second); output_file.reset(); // provide some feedback - printf("File (%s) written, %s bytes\n", output_file_str->second->c_str(), big_int_string(buffer.size()).c_str()); + util::stream_format(std::cout, "File (%s) written, %s bytes\n", *output_file_str->second, big_int_string(buffer.size())); } else { @@ -3176,13 +3371,13 @@ static void do_dump_metadata(parameters_map ¶ms) static void do_list_templates(parameters_map ¶ms) { - printf("\n"); - printf("ID Manufacturer Model Cylinders Heads Sectors Sector Size Total Size\n"); - printf("------------------------------------------------------------------------------------\n"); + util::stream_format(std::cout, "\n"); + util::stream_format(std::cout, "ID Manufacturer Model Cylinders Heads Sectors Sector Size Total Size\n"); + util::stream_format(std::cout, "------------------------------------------------------------------------------------\n"); for (int id = 0; id < std::size(s_hd_templates); id++) { - printf("%2d %-13s %-15s %9d %5d %7d %11d %7d MB\n", + util::stream_format(std::cout, "%2d %-13s %-15s %9d %5d %7d %11d %7d MB\n", id, s_hd_templates[id].manufacturer, s_hd_templates[id].model, @@ -3203,10 +3398,11 @@ static void do_list_templates(parameters_map ¶ms) int CLIB_DECL main(int argc, char *argv[]) { const std::vector<std::string> args = osd_get_command_line(argc, argv); + chdman_osd_output osdoutput; // print the header extern const char build_version[]; - printf("chdman - MAME Compressed Hunks of Data (CHD) manager %s\n", build_version); + util::stream_format(std::cout, "chdman - MAME Compressed Hunks of Data (CHD) manager %s\n", build_version); // handle help specially if (args.size() < 2) @@ -3223,6 +3419,7 @@ int CLIB_DECL main(int argc, char *argv[]) // iterate over commands to find our match for (auto & s_command : s_commands) + { if (command == s_command.name) { const command_description &desc = s_command; @@ -3242,12 +3439,10 @@ int CLIB_DECL main(int argc, char *argv[]) // iterate over valid options int valid; - for (valid = 0; valid < std::size(desc.valid_options); valid++) + for (valid = 0; (valid < std::size(desc.valid_options)) && desc.valid_options[valid]; valid++) { // reduce to the option name const char *validname = desc.valid_options[valid]; - if (validname == nullptr) - break; if (*validname == REQUIRED[0]) validname++; @@ -3280,8 +3475,8 @@ int CLIB_DECL main(int argc, char *argv[]) } // if not valid, error - if (valid == std::size(desc.valid_options)) - return print_help(args[0], desc, "Option not valid for this command"); + if ((valid == std::size(desc.valid_options)) || !desc.valid_options[valid]) + return print_help(args[0], desc, string_format("Option '%s' not valid for this command", arg).c_str()); } // make sure we got all our required parameters @@ -3302,20 +3497,21 @@ int CLIB_DECL main(int argc, char *argv[]) } catch (std::error_condition const &err) { - fprintf(stderr, "CHD error occurred (main): %s\n", err.message().c_str()); + util::stream_format(std::cerr, "CHD error occurred (main): %s\n", err.message()); return 1; } catch (fatal_error &err) { - fprintf(stderr, "Fatal error occurred: %d\n", err.error()); + util::stream_format(std::cerr, "Fatal error occurred: %d\n", err.error()); return err.error(); } catch (std::exception& ex) { - fprintf(stderr, "Unhandled exception: %s\n", ex.what()); + util::stream_format(std::cerr, "Unhandled exception: %s\n", ex.what()); return 1; } } + } // print generic help if nothing found return print_help(args[0]); diff --git a/src/tools/floptool.cpp b/src/tools/floptool.cpp index ba573e0a0cd..9ac9c3231ae 100644 --- a/src/tools/floptool.cpp +++ b/src/tools/floptool.cpp @@ -302,7 +302,7 @@ static void dir_scan(fs::filesystem_t *fs, u32 depth, const std::vector<std::str head += " "; auto [err, contents] = fs->directory_contents(path); if(err) - return; + return; // FIXME: don't swallow errors for(const auto &c : contents) { size_t id = entries.size(); entries.resize(id+1); @@ -472,10 +472,7 @@ static int generic_read(image_handler &ih, const char *srcpath, const char *dstp std::vector<std::string> path = ih.path_split(srcpath); auto [err, dfork] = fs->file_read(path); if(err) { - if(err == fs::ERR_NOT_FOUND) - fprintf(stderr, "File not found.\n"); - else - fprintf(stderr, "Unknown error (%d).\n", err); + fprintf(stderr, "File reading failed: %s\n", err.message().c_str()); return 1; } @@ -568,14 +565,14 @@ static int generic_write(image_handler &ih, const char *srcpath, const char *dst auto [err, meta] = fs->metadata(path); std::ignore = meta; - if(err) { + if(err == fs::error::not_found) { fs::meta_data meta; meta.set(fs::meta_name::name, path.back()); auto dpath = path; dpath.pop_back(); err = fs->file_create(dpath, meta); if(err) { - fprintf(stderr, "File creation failure.\n"); + fprintf(stderr, "File creation failed: %s\n", err.message().c_str()); return 1; } } @@ -583,7 +580,7 @@ static int generic_write(image_handler &ih, const char *srcpath, const char *dst auto dfork = image_handler::fload(srcpath); err = fs->file_write(path, dfork); if(err) { - fprintf(stderr, "File writing failure.\n"); + fprintf(stderr, "File writing failed: %s\n", err.message().c_str()); return 1; } @@ -594,7 +591,7 @@ static int generic_write(image_handler &ih, const char *srcpath, const char *dst auto rfork = image_handler::fload_rsrc(rpath); if(!rfork.empty()) { err = fs->file_rsrc_write(path, rfork); - fprintf(stderr, "File resource fork writing failure.\n"); + fprintf(stderr, "File resource fork writing failed: %s\n", err.message().c_str()); return 1; } } @@ -725,7 +722,7 @@ int CLIB_DECL main(int argc, char *argv[]) return 1; } } catch(const std::exception &err) { - fprintf(stderr, "Error: %s", err.what()); + fprintf(stderr, "Error: %s\n", err.what()); return 1; } } diff --git a/src/tools/image_handler.cpp b/src/tools/image_handler.cpp index 60ab72e61f8..14976516e1c 100644 --- a/src/tools/image_handler.cpp +++ b/src/tools/image_handler.cpp @@ -15,6 +15,8 @@ #include "multibyte.h" #include "strformat.h" +#include <algorithm> + // Format enumeration @@ -43,7 +45,7 @@ namespace { struct fs_enum : public fs::manager_t::floppy_enumerator { filesystem_format *m_format; - fs_enum(filesystem_format *format, const std::vector<u32> &variants) : fs::manager_t::floppy_enumerator(floppy_image::FF_UNKNOWN, variants), m_format(format) {} + fs_enum(filesystem_format *format, u32 form_factor, const std::vector<u32> &variants) : fs::manager_t::floppy_enumerator(form_factor, variants), m_format(format) {} virtual void add_format(const floppy_image_format_t &type, u32 image_size, const char *name, const char *description) override { m_format->m_floppy = true; @@ -65,7 +67,7 @@ void formats_table::init() mame_formats_full_list(en); for(auto &f : filesystem_formats) { - fs_enum fen(f.get(), variants); + fs_enum fen(f.get(), floppy_image::FF_UNKNOWN, variants); f->m_manager->enumerate_f(fen); } @@ -244,6 +246,9 @@ std::vector<std::pair<u8, const floppy_format_info *>> image_handler::identify(c res.emplace_back(std::make_pair(score, e.second)); } + // Sort results by decreasing score + std::stable_sort(res.begin(), res.end(), [](const auto &a, const auto &b) { return a.first > b.first; }); + return res; } @@ -295,8 +300,14 @@ void image_handler::floppy_create(const floppy_create_info &format, fs::meta_dat bool image_handler::floppy_mount_fs(const filesystem_format &format) { + // Create a restricted copy of the format list based on the known form factor and variant + filesystem_format fmtcopy(format.m_manager, format.m_category); + std::vector<u32> const var(1, m_floppy_image.get_variant()); + fs_enum fen(&fmtcopy, m_floppy_image.get_form_factor(), var); + format.m_manager->enumerate_f(fen); + m_floppy_fs_converter = nullptr; - for(const auto &ci : format.m_floppy_create) { + for(const auto &ci : fmtcopy.m_floppy_create) { if(ci->m_type != m_floppy_fs_converter) { std::vector<uint32_t> variants; m_floppy_fs_converter = ci->m_type; diff --git a/src/tools/imgtool/filtbas.cpp b/src/tools/imgtool/filtbas.cpp index 8a84811540d..f4098202c32 100644 --- a/src/tools/imgtool/filtbas.cpp +++ b/src/tools/imgtool/filtbas.cpp @@ -32,7 +32,7 @@ CONSTANTS ***************************************************************************/ -#define EOLN (CRLF == 1 ? "\r" : (CRLF == 2 ? "\n" : (CRLF == 3 ? "\r\n" : NULL))) +#define EOLN (CRLF == 1 ? "\r" : (CRLF == 2 ? "\n" : (CRLF == 3 ? "\r\n" : nullptr))) @@ -1033,58 +1033,58 @@ static const char *const basic_10[] = /* "BASIC 1.0" - supported by pet */ "LEFT$", /* 0xc8 */ "RIGHT$", /* 0xc9 */ "MID$", /* 0xca */ - NULL, /* 0xcb */ - NULL, /* 0xcc */ - NULL, /* 0xcd */ - NULL, /* 0xce */ - NULL, /* 0xcf */ - NULL, /* 0xd0 */ - NULL, /* 0xd1 */ - NULL, /* 0xd2 */ - NULL, /* 0xd3 */ - NULL, /* 0xd4 */ - NULL, /* 0xd5 */ - NULL, /* 0xd6 */ - NULL, /* 0xd7 */ - NULL, /* 0xd8 */ - NULL, /* 0xd9 */ - NULL, /* 0xda */ - NULL, /* 0xdb */ - NULL, /* 0xdc */ - NULL, /* 0xdd */ - NULL, /* 0xde */ - NULL, /* 0xdf */ - NULL, /* 0xe0 */ - NULL, /* 0xe1 */ - NULL, /* 0xe2 */ - NULL, /* 0xe3 */ - NULL, /* 0xe4 */ - NULL, /* 0xe5 */ - NULL, /* 0xe6 */ - NULL, /* 0xe7 */ - NULL, /* 0xe8 */ - NULL, /* 0xe9 */ - NULL, /* 0xea */ - NULL, /* 0xeb */ - NULL, /* 0xec */ - NULL, /* 0xed */ - NULL, /* 0xee */ - NULL, /* 0xef */ - NULL, /* 0xf0 */ - NULL, /* 0xf1 */ - NULL, /* 0xf2 */ - NULL, /* 0xf3 */ - NULL, /* 0xf4 */ - NULL, /* 0xf5 */ - NULL, /* 0xf6 */ - NULL, /* 0xf7 */ - NULL, /* 0xf8 */ - NULL, /* 0xf9 */ - NULL, /* 0xfa */ - NULL, /* 0xfb */ - NULL, /* 0xfc */ - NULL, /* 0xfd */ - NULL, /* 0xfe */ + nullptr, /* 0xcb */ + nullptr, /* 0xcc */ + nullptr, /* 0xcd */ + nullptr, /* 0xce */ + nullptr, /* 0xcf */ + nullptr, /* 0xd0 */ + nullptr, /* 0xd1 */ + nullptr, /* 0xd2 */ + nullptr, /* 0xd3 */ + nullptr, /* 0xd4 */ + nullptr, /* 0xd5 */ + nullptr, /* 0xd6 */ + nullptr, /* 0xd7 */ + nullptr, /* 0xd8 */ + nullptr, /* 0xd9 */ + nullptr, /* 0xda */ + nullptr, /* 0xdb */ + nullptr, /* 0xdc */ + nullptr, /* 0xdd */ + nullptr, /* 0xde */ + nullptr, /* 0xdf */ + nullptr, /* 0xe0 */ + nullptr, /* 0xe1 */ + nullptr, /* 0xe2 */ + nullptr, /* 0xe3 */ + nullptr, /* 0xe4 */ + nullptr, /* 0xe5 */ + nullptr, /* 0xe6 */ + nullptr, /* 0xe7 */ + nullptr, /* 0xe8 */ + nullptr, /* 0xe9 */ + nullptr, /* 0xea */ + nullptr, /* 0xeb */ + nullptr, /* 0xec */ + nullptr, /* 0xed */ + nullptr, /* 0xee */ + nullptr, /* 0xef */ + nullptr, /* 0xf0 */ + nullptr, /* 0xf1 */ + nullptr, /* 0xf2 */ + nullptr, /* 0xf3 */ + nullptr, /* 0xf4 */ + nullptr, /* 0xf5 */ + nullptr, /* 0xf6 */ + nullptr, /* 0xf7 */ + nullptr, /* 0xf8 */ + nullptr, /* 0xf9 */ + nullptr, /* 0xfa */ + nullptr, /* 0xfb */ + nullptr, /* 0xfc */ + nullptr, /* 0xfd */ + nullptr, /* 0xfe */ "{PI}" /* 0xff - A single character shaped as greek lowercase 'PI' */ }; @@ -1166,57 +1166,57 @@ static const char *const basic_20[] = /* "BASIC 2.0" - supported by vic20 & clon "RIGHT$", /* 0xc9 */ "MID$", /* 0xca */ "GO", /* 0xcb */ - NULL, /* 0xcc */ - NULL, /* 0xcd */ - NULL, /* 0xce */ - NULL, /* 0xcf */ - NULL, /* 0xd0 */ - NULL, /* 0xd1 */ - NULL, /* 0xd2 */ - NULL, /* 0xd3 */ - NULL, /* 0xd4 */ - NULL, /* 0xd5 */ - NULL, /* 0xd6 */ - NULL, /* 0xd7 */ - NULL, /* 0xd8 */ - NULL, /* 0xd9 */ - NULL, /* 0xda */ - NULL, /* 0xdb */ - NULL, /* 0xdc */ - NULL, /* 0xdd */ - NULL, /* 0xde */ - NULL, /* 0xdf */ - NULL, /* 0xe0 */ - NULL, /* 0xe1 */ - NULL, /* 0xe2 */ - NULL, /* 0xe3 */ - NULL, /* 0xe4 */ - NULL, /* 0xe5 */ - NULL, /* 0xe6 */ - NULL, /* 0xe7 */ - NULL, /* 0xe8 */ - NULL, /* 0xe9 */ - NULL, /* 0xea */ - NULL, /* 0xeb */ - NULL, /* 0xec */ - NULL, /* 0xed */ - NULL, /* 0xee */ - NULL, /* 0xef */ - NULL, /* 0xf0 */ - NULL, /* 0xf1 */ - NULL, /* 0xf2 */ - NULL, /* 0xf3 */ - NULL, /* 0xf4 */ - NULL, /* 0xf5 */ - NULL, /* 0xf6 */ - NULL, /* 0xf7 */ - NULL, /* 0xf8 */ - NULL, /* 0xf9 */ - NULL, /* 0xfa */ - NULL, /* 0xfb */ - NULL, /* 0xfc */ - NULL, /* 0xfd */ - NULL, /* 0xfe */ + nullptr, /* 0xcc */ + nullptr, /* 0xcd */ + nullptr, /* 0xce */ + nullptr, /* 0xcf */ + nullptr, /* 0xd0 */ + nullptr, /* 0xd1 */ + nullptr, /* 0xd2 */ + nullptr, /* 0xd3 */ + nullptr, /* 0xd4 */ + nullptr, /* 0xd5 */ + nullptr, /* 0xd6 */ + nullptr, /* 0xd7 */ + nullptr, /* 0xd8 */ + nullptr, /* 0xd9 */ + nullptr, /* 0xda */ + nullptr, /* 0xdb */ + nullptr, /* 0xdc */ + nullptr, /* 0xdd */ + nullptr, /* 0xde */ + nullptr, /* 0xdf */ + nullptr, /* 0xe0 */ + nullptr, /* 0xe1 */ + nullptr, /* 0xe2 */ + nullptr, /* 0xe3 */ + nullptr, /* 0xe4 */ + nullptr, /* 0xe5 */ + nullptr, /* 0xe6 */ + nullptr, /* 0xe7 */ + nullptr, /* 0xe8 */ + nullptr, /* 0xe9 */ + nullptr, /* 0xea */ + nullptr, /* 0xeb */ + nullptr, /* 0xec */ + nullptr, /* 0xed */ + nullptr, /* 0xee */ + nullptr, /* 0xef */ + nullptr, /* 0xf0 */ + nullptr, /* 0xf1 */ + nullptr, /* 0xf2 */ + nullptr, /* 0xf3 */ + nullptr, /* 0xf4 */ + nullptr, /* 0xf5 */ + nullptr, /* 0xf6 */ + nullptr, /* 0xf7 */ + nullptr, /* 0xf8 */ + nullptr, /* 0xf9 */ + nullptr, /* 0xfa */ + nullptr, /* 0xfb */ + nullptr, /* 0xfc */ + nullptr, /* 0xfd */ + nullptr, /* 0xfe */ "{PI}" /* 0xff - A single character shaped as greek lowercase 'PI' */ }; @@ -2971,7 +2971,7 @@ static imgtoolerr_t cocobas_writefile(imgtool::partition &partition, const char return basic_writefile(&cocobas_tokens, partition, filename, fork, sourcef, opts); } -void filter_cocobas_getinfo(uint32_t state, union filterinfo *info) +void filter_cocobas_getinfo(uint32_t state, imgtool::filterinfo *info) { switch(state) { @@ -3017,7 +3017,7 @@ static imgtoolerr_t dragonbas_writefile(imgtool::partition &partition, const cha return basic_writefile(&dragonbas_tokens, partition, filename, fork, sourcef, opts); } -void filter_dragonbas_getinfo(uint32_t state, union filterinfo *info) +void filter_dragonbas_getinfo(uint32_t state, imgtool::filterinfo *info) { switch(state) { @@ -3064,7 +3064,7 @@ static imgtoolerr_t vzbas_writefile(imgtool::partition &partition, const char *f return basic_writefile(&vzbas_tokens, partition, filename, fork, sourcef, opts); } -void filter_vzbas_getinfo(uint32_t state, union filterinfo *info) +void filter_vzbas_getinfo(uint32_t state, imgtool::filterinfo *info) { switch(state) { @@ -3110,7 +3110,7 @@ static imgtoolerr_t bml3bas_writefile(imgtool::partition &partition, const char return basic_writefile(&bml3bas_tokens, partition, filename, fork, sourcef, opts); } -void filter_bml3bas_getinfo(uint32_t state, union filterinfo *info) +void filter_bml3bas_getinfo(uint32_t state, imgtool::filterinfo *info) { switch(state) { diff --git a/src/tools/imgtool/filteoln.cpp b/src/tools/imgtool/filteoln.cpp index 6d80e9b2180..41f11769747 100644 --- a/src/tools/imgtool/filteoln.cpp +++ b/src/tools/imgtool/filteoln.cpp @@ -13,7 +13,7 @@ #include <cstring> -#define EOLN (CRLF == 1 ? "\r" : (CRLF == 2 ? "\n" : (CRLF == 3 ? "\r\n" : NULL))) +#define EOLN (CRLF == 1 ? "\r" : (CRLF == 2 ? "\n" : (CRLF == 3 ? "\r\n" : nullptr))) @@ -96,7 +96,7 @@ static imgtoolerr_t ascii_writefile(imgtool::partition &partition, const char *f -void filter_eoln_getinfo(uint32_t state, union filterinfo *info) +void filter_eoln_getinfo(uint32_t state, imgtool::filterinfo *info) { switch(state) { diff --git a/src/tools/imgtool/filter.cpp b/src/tools/imgtool/filter.cpp index 9ecffb19845..9df7c3c1692 100644 --- a/src/tools/imgtool/filter.cpp +++ b/src/tools/imgtool/filter.cpp @@ -14,33 +14,33 @@ /* ----------------------------------------------------------------------- */ -int64_t filter_get_info_int(filter_getinfoproc get_info, uint32_t state) +int64_t filter_get_info_int(imgtool::filter_getinfoproc get_info, uint32_t state) { - union filterinfo info; + imgtool::filterinfo info; info.i = 0; get_info(state, &info); return info.i; } -void *filter_get_info_ptr(filter_getinfoproc get_info, uint32_t state) +void *filter_get_info_ptr(imgtool::filter_getinfoproc get_info, uint32_t state) { - union filterinfo info; + imgtool::filterinfo info; info.p = nullptr; get_info(state, &info); return info.p; } -void *filter_get_info_fct(filter_getinfoproc get_info, uint32_t state) +void *filter_get_info_fct(imgtool::filter_getinfoproc get_info, uint32_t state) { - union filterinfo info; + imgtool::filterinfo info; info.f = nullptr; get_info(state, &info); return info.f; } -const char *filter_get_info_string(filter_getinfoproc get_info, uint32_t state) +const char *filter_get_info_string(imgtool::filter_getinfoproc get_info, uint32_t state) { - union filterinfo info; + imgtool::filterinfo info; info.s = nullptr; get_info(state, &info); return info.s; @@ -48,7 +48,7 @@ const char *filter_get_info_string(filter_getinfoproc get_info, uint32_t state) /* ----------------------------------------------------------------------- */ -const filter_getinfoproc filters[] = +const imgtool::filter_getinfoproc filters[] = { filter_eoln_getinfo, filter_cocobas_getinfo, @@ -66,14 +66,11 @@ const filter_getinfoproc filters[] = -filter_getinfoproc filter_lookup(const char *name) +imgtool::filter_getinfoproc filter_lookup(const char *name) { - int i; - const char *filter_name; - - for (i = 0; filters[i]; i++) + for (int i = 0; filters[i]; i++) { - filter_name = filter_get_info_string(filters[i], FILTINFO_STR_NAME); + char const *const filter_name = filter_get_info_string(filters[i], FILTINFO_STR_NAME); if (!strcmp(name, filter_name)) return filters[i]; } diff --git a/src/tools/imgtool/filter.h b/src/tools/imgtool/filter.h index 75c131906d0..0b9b1f14884 100644 --- a/src/tools/imgtool/filter.h +++ b/src/tools/imgtool/filter.h @@ -8,8 +8,10 @@ ***************************************************************************/ -#ifndef FILTER_H -#define FILTER_H +#ifndef MAME_TOOLS_IMGTOOL_FILTER_H +#define MAME_TOOLS_IMGTOOL_FILTER_H + +#pragma once #include "library.h" @@ -34,30 +36,30 @@ enum FILTINFO_STR_EXTENSION }; -extern const filter_getinfoproc filters[]; +extern const imgtool::filter_getinfoproc filters[]; -filter_getinfoproc filter_lookup(const char *name); +imgtool::filter_getinfoproc filter_lookup(const char *name); /* ----------------------------------------------------------------------- */ -int64_t filter_get_info_int(filter_getinfoproc get_info, uint32_t state); -void *filter_get_info_ptr(filter_getinfoproc get_info, uint32_t state); -void *filter_get_info_fct(filter_getinfoproc get_info, uint32_t state); -const char *filter_get_info_string(filter_getinfoproc get_info, uint32_t state); +int64_t filter_get_info_int(imgtool::filter_getinfoproc get_info, uint32_t state); +void *filter_get_info_ptr(imgtool::filter_getinfoproc get_info, uint32_t state); +void *filter_get_info_fct(imgtool::filter_getinfoproc get_info, uint32_t state); +const char *filter_get_info_string(imgtool::filter_getinfoproc get_info, uint32_t state); /* ----------------------------------------------------------------------- */ -extern void filter_eoln_getinfo(uint32_t state, union filterinfo *info); -extern void filter_cocobas_getinfo(uint32_t state, union filterinfo *info); -extern void filter_dragonbas_getinfo(uint32_t state, union filterinfo *info); -extern void filter_macbinary_getinfo(uint32_t state, union filterinfo *info); -extern void filter_vzsnapshot_getinfo(uint32_t state, union filterinfo *info); -extern void filter_vzbas_getinfo(uint32_t state, union filterinfo *info); -extern void filter_thombas5_getinfo(uint32_t state, union filterinfo *info); -extern void filter_thombas7_getinfo(uint32_t state, union filterinfo *info); -extern void filter_thombas128_getinfo(uint32_t state, union filterinfo *info); -extern void filter_thomcrypt_getinfo(uint32_t state, union filterinfo *info); -extern void filter_bml3bas_getinfo(uint32_t state, union filterinfo *info); -extern void filter_hp9845data_getinfo(uint32_t state, union filterinfo *info); - -#endif /* FILTER_H */ +extern void filter_eoln_getinfo(uint32_t state, imgtool::filterinfo *info); +extern void filter_cocobas_getinfo(uint32_t state, imgtool::filterinfo *info); +extern void filter_dragonbas_getinfo(uint32_t state, imgtool::filterinfo *info); +extern void filter_macbinary_getinfo(uint32_t state, imgtool::filterinfo *info); +extern void filter_vzsnapshot_getinfo(uint32_t state, imgtool::filterinfo *info); +extern void filter_vzbas_getinfo(uint32_t state, imgtool::filterinfo *info); +extern void filter_thombas5_getinfo(uint32_t state, imgtool::filterinfo *info); +extern void filter_thombas7_getinfo(uint32_t state, imgtool::filterinfo *info); +extern void filter_thombas128_getinfo(uint32_t state, imgtool::filterinfo *info); +extern void filter_thomcrypt_getinfo(uint32_t state, imgtool::filterinfo *info); +extern void filter_bml3bas_getinfo(uint32_t state, imgtool::filterinfo *info); +extern void filter_hp9845data_getinfo(uint32_t state, imgtool::filterinfo *info); + +#endif // MAME_TOOLS_IMGTOOL_FILTER_H diff --git a/src/tools/imgtool/imgtool.cpp b/src/tools/imgtool/imgtool.cpp index 6a3fe511fd2..e10558dcce1 100644 --- a/src/tools/imgtool/imgtool.cpp +++ b/src/tools/imgtool/imgtool.cpp @@ -260,45 +260,39 @@ void imgtool_warn(const char *format, ...) static imgtoolerr_t evaluate_module(const char *fname, const imgtool_module *module, float &result) { imgtoolerr_t err; - imgtool::image::ptr image; - imgtool::partition::ptr partition; - imgtool::directory::ptr imageenum; - imgtool_dirent ent; - float current_result; result = 0.0; + imgtool::image::ptr image; err = imgtool::image::open(module, fname, OSD_FOPEN_READ, image); - if (err) - goto done; - - if (image) + if (!err && image) { - current_result = module->open_is_strict ? 0.9 : 0.5; - + imgtool::partition::ptr partition; + imgtool::directory::ptr imageenum; err = imgtool::partition::open(*image, 0, partition); - if (err) - goto done; + if (!err) + err = imgtool::directory::open(*partition, "", imageenum); - err = imgtool::directory::open(*partition, "", imageenum); - if (err) - goto done; - - memset(&ent, 0, sizeof(ent)); - do + if (!err) { - err = imageenum->get_next(ent); - if (err) - goto done; + float current_result = module->open_is_strict ? 0.9 : 0.5; - if (ent.corrupt) - current_result = (current_result * 99 + 1.00f) / 100; - else - current_result = (current_result + 1.00f) / 2; - } - while(!ent.eof); + imgtool_dirent ent; + do + { + err = imageenum->get_next(ent); + if (err) + goto done; - result = current_result; + if (ent.corrupt) + current_result = (current_result * 99 + 1.00f) / 100; + else + current_result = (current_result + 1.00f) / 2; + } + while (!ent.eof); + + result = current_result; + } } done: @@ -589,8 +583,8 @@ imgtool::partition::partition(imgtool::image &image, const imgtool_class &imgcla m_set_attrs = (imgtoolerr_t(*)(imgtool::partition &, const char *, const uint32_t *, const imgtool_attribute *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_SET_ATTRS); m_attr_name = (imgtoolerr_t(*)(uint32_t, const imgtool_attribute *, char *, size_t)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_ATTR_NAME); m_get_iconinfo = (imgtoolerr_t(*)(imgtool::partition &, const char *, imgtool_iconinfo *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_GET_ICON_INFO); - m_suggest_transfer = (imgtoolerr_t(*)(imgtool::partition &, const char *, imgtool_transfer_suggestion *, size_t)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_SUGGEST_TRANSFER); - m_get_chain = (imgtoolerr_t(*)(imgtool::partition &, const char *, imgtool_chainent *, size_t)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_GET_CHAIN); + m_suggest_transfer = (imgtoolerr_t(*)(imgtool::partition &, const char *, imgtool::transfer_suggestion *, size_t)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_SUGGEST_TRANSFER); + m_get_chain = (imgtoolerr_t(*)(imgtool::partition &, const char *, imgtool::chainent *, size_t)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_GET_CHAIN); m_writefile_optguide = (const util::option_guide *) imgtool_get_info_ptr(&imgclass, IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE); const char *writefile_optspec = (const char *)imgtool_get_info_ptr(&imgclass, IMGTOOLINFO_STR_WRITEFILE_OPTSPEC); @@ -1293,37 +1287,31 @@ done: imgtoolerr_t imgtool::partition::get_file_size(const char *fname, uint64_t &filesize) { imgtoolerr_t err; - imgtool::directory::ptr imgenum; - imgtool_dirent ent; - const char *path; - path = nullptr; /* TODO: Need to parse off the path */ - - filesize = ~((uint64_t) 0); - memset(&ent, 0, sizeof(ent)); + filesize = ~uint64_t(0); + imgtool::directory::ptr imgenum; + const char *path = nullptr; // TODO: Need to parse off the path err = imgtool::directory::open(*this, path, imgenum); if (err) - goto done; + return err; + imgtool_dirent ent; do { err = imgenum->get_next(ent); if (err) - goto done; + return err; if (!core_stricmp(fname, ent.filename)) { filesize = ent.filesize; - goto done; + return err; } } while(ent.filename[0]); - err = (imgtoolerr_t)IMGTOOLERR_FILENOTFOUND; - -done: - return err; + return (imgtoolerr_t)IMGTOOLERR_FILENOTFOUND; } @@ -1466,12 +1454,10 @@ imgtoolerr_t imgtool::partition::get_icon_info(const char *path, imgtool_iconinf //------------------------------------------------- imgtoolerr_t imgtool::partition::suggest_file_filters(const char *path, - imgtool::stream *stream, imgtool_transfer_suggestion *suggestions, size_t suggestions_length) + imgtool::stream *stream, imgtool::transfer_suggestion *suggestions, size_t suggestions_length) { imgtoolerr_t err; - int i, j; - imgtoolerr_t (*check_stream)(imgtool::stream &stream, imgtool_suggestion_viability_t *viability); - size_t position; + imgtoolerr_t (*check_stream)(imgtool::stream &stream, imgtool::suggestion_viability_t *viability); // clear out buffer memset(suggestions, 0, sizeof(*suggestions) * suggestions_length); @@ -1493,15 +1479,15 @@ imgtoolerr_t imgtool::partition::suggest_file_filters(const char *path, // loop on resulting suggestions, and do the following: // 1. Call check_stream if present, and remove disqualified streams // 2. Fill in missing descriptions - i = j = 0; + int i = 0, j = 0; while(suggestions[i].viability) { if (stream && suggestions[i].filter) { - check_stream = (imgtoolerr_t (*)(imgtool::stream &, imgtool_suggestion_viability_t *)) filter_get_info_fct(suggestions[i].filter, FILTINFO_PTR_CHECKSTREAM); + check_stream = (imgtoolerr_t (*)(imgtool::stream &, imgtool::suggestion_viability_t *)) filter_get_info_fct(suggestions[i].filter, FILTINFO_PTR_CHECKSTREAM); if (check_stream) { - position = stream->tell(); + size_t const position = stream->tell(); err = check_stream(*stream, &suggestions[i].viability); stream->seek(position, SEEK_SET); if (err) @@ -1529,7 +1515,7 @@ imgtoolerr_t imgtool::partition::suggest_file_filters(const char *path, } i++; } - suggestions[j].viability = (imgtool_suggestion_viability_t)0; + suggestions[j].viability = (imgtool::suggestion_viability_t)0; return IMGTOOLERR_SUCCESS; } @@ -1540,17 +1526,15 @@ imgtoolerr_t imgtool::partition::suggest_file_filters(const char *path, // chain for a file or directory on a partition //------------------------------------------------- -imgtoolerr_t imgtool::partition::get_chain(const char *path, imgtool_chainent *chain, size_t chain_size) +imgtoolerr_t imgtool::partition::get_chain(const char *path, imgtool::chainent *chain, size_t chain_size) { - size_t i; - assert(chain_size > 0); if (!m_get_chain) return imgtoolerr_t(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); // initialize the chain array, so the module's get_chain function can be lazy - for (i = 0; i < chain_size; i++) + for (int i = 0; i < chain_size; i++) { chain[i].level = 0; chain[i].block = ~0; @@ -1569,7 +1553,7 @@ imgtoolerr_t imgtool::partition::get_chain(const char *path, imgtool_chainent *c imgtoolerr_t imgtool::partition::get_chain_string(const char *path, char *buffer, size_t buffer_len) { imgtoolerr_t err; - imgtool_chainent chain[512]; + imgtool::chainent chain[512]; uint64_t last_block; uint8_t cur_level = 0; int len, i; @@ -2318,9 +2302,8 @@ imgtoolerr_t imgtool::directory::get_next(imgtool_dirent &ent) { imgtoolerr_t err; - // This makes it so that drivers don't have to take care of clearing - // the attributes if they don't apply - memset(&ent, 0, sizeof(ent)); + // This makes it so that drivers don't have to take care of clearing the attributes if they don't apply + ent = imgtool_dirent(); err = m_partition.m_next_enum(*this, ent); if (err) @@ -2370,7 +2353,7 @@ void unknown_partition_get_info(const imgtool_class *imgclass, uint32_t state, u { switch(state) { - /* --- the following bits of info are returned as NULL-terminated strings --- */ + /* --- the following bits of info are returned as NUL-terminated strings --- */ case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "unknown"); break; case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "Unknown partition type"); break; } diff --git a/src/tools/imgtool/imgtool.h b/src/tools/imgtool/imgtool.h index 4a66d7f249d..4ad7fc5479d 100644 --- a/src/tools/imgtool/imgtool.h +++ b/src/tools/imgtool/imgtool.h @@ -8,8 +8,10 @@ ***************************************************************************/ -#ifndef IMGTOOL_H -#define IMGTOOL_H +#ifndef MAME_TOOLS_IMGTOOL_IMGTOOL_H +#define MAME_TOOLS_IMGTOOL_IMGTOOL_H + +#pragma once #include "library.h" #include "stream.h" @@ -164,11 +166,11 @@ namespace imgtool imgtoolerr_t put_file_attribute(const char *path, uint32_t attr, const imgtool_attribute &value); void get_attribute_name(uint32_t attribute, const imgtool_attribute *attr_value, char *buffer, size_t buffer_len); imgtoolerr_t get_icon_info(const char *path, imgtool_iconinfo *iconinfo); - imgtoolerr_t suggest_file_filters(const char *path, imgtool::stream *stream, imgtool_transfer_suggestion *suggestions, size_t suggestions_length); + imgtoolerr_t suggest_file_filters(const char *path, imgtool::stream *stream, imgtool::transfer_suggestion *suggestions, size_t suggestions_length); imgtoolerr_t get_block_size(uint32_t &length); imgtoolerr_t read_block(uint64_t block, void *buffer); imgtoolerr_t write_block(uint64_t block, const void *buffer); - imgtoolerr_t get_chain(const char *path, imgtool_chainent *chain, size_t chain_size); + imgtoolerr_t get_chain(const char *path, imgtool::chainent *chain, size_t chain_size); imgtoolerr_t get_chain_string(const char *path, char *buffer, size_t buffer_len); imgtool_partition_features get_features() const; void * get_info_ptr(uint32_t state); @@ -213,8 +215,8 @@ namespace imgtool std::function<imgtoolerr_t(imgtool::partition &partition, const char *path, const uint32_t *attrs, const imgtool_attribute *values)> m_set_attrs; std::function<imgtoolerr_t(uint32_t attribute, const imgtool_attribute *attr, char *buffer, size_t buffer_len)> m_attr_name; std::function<imgtoolerr_t(imgtool::partition &partition, const char *path, imgtool_iconinfo *iconinfo)> m_get_iconinfo; - std::function<imgtoolerr_t(imgtool::partition &partition, const char *path, imgtool_transfer_suggestion *suggestions, size_t suggestions_length)> m_suggest_transfer; - std::function<imgtoolerr_t(imgtool::partition &partition, const char *path, imgtool_chainent *chain, size_t chain_size)> m_get_chain; + std::function<imgtoolerr_t(imgtool::partition &partition, const char *path, imgtool::transfer_suggestion *suggestions, size_t suggestions_length)> m_suggest_transfer; + std::function<imgtoolerr_t(imgtool::partition &partition, const char *path, imgtool::chainent *chain, size_t chain_size)> m_get_chain; const util::option_guide *m_writefile_optguide; std::string m_writefile_optspec; @@ -262,4 +264,4 @@ char *strncpyz(char *dest, const char *source, size_t len); void rtrim(char *buf); std::string extract_padded_filename(const char *source, size_t filename_length, size_t extension_length, char pad = ' '); -#endif /* IMGTOOL_H */ +#endif // MAME_TOOLS_IMGTOOL_IMGTOOL_H diff --git a/src/tools/imgtool/library.h b/src/tools/imgtool/library.h index 312d3bbe30f..023b5fb948f 100644 --- a/src/tools/imgtool/library.h +++ b/src/tools/imgtool/library.h @@ -22,6 +22,7 @@ #include "timeconv.h" #include "utilfwd.h" +#include <algorithm> #include <chrono> #include <cstdint> #include <ctime> @@ -32,16 +33,15 @@ #include <vector> -namespace imgtool -{ - class image; - class partition; - class directory; - class charconverter; - class stream; -}; +namespace imgtool { + +class image; +class partition; +class directory; +class charconverter; +class stream; -enum imgtool_suggestion_viability_t +enum suggestion_viability_t { SUGGESTION_END, SUGGESTION_POSSIBLE, @@ -57,162 +57,171 @@ union filterinfo imgtoolerr_t (*read_file)(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &destf); imgtoolerr_t (*write_file)(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &sourcef, util::option_resolution *opts); - imgtoolerr_t (*check_stream)(imgtool::stream &stream, imgtool_suggestion_viability_t *viability); + imgtoolerr_t (*check_stream)(imgtool::stream &stream, suggestion_viability_t *viability); }; typedef void (*filter_getinfoproc)(uint32_t state, union filterinfo *info); -namespace imgtool +class datetime { - class datetime - { - public: - typedef util::arbitrary_clock<std::int64_t, 1600, 1, 1, 0, 0, 0, std::ratio<1, 10000000> > imgtool_clock; +public: + typedef util::arbitrary_clock<std::int64_t, 1600, 1, 1, 0, 0, 0, std::ratio<1, 10000000> > imgtool_clock; - enum datetime_type - { - NONE, - LOCAL, - GMT - }; + enum datetime_type + { + NONE, + LOCAL, + GMT + }; - datetime() - : m_type(datetime_type::NONE) - { - } + datetime() + : m_type(datetime_type::NONE) + { + } - template<typename Rep, int Y, int M, int D, int H, int N, int S, typename Ratio> - datetime(datetime_type type, std::chrono::time_point<util::arbitrary_clock<Rep, Y, M, D, H, N, S, Ratio> > tp) - : m_type(type) - , m_time_point(imgtool_clock::from_arbitrary_time_point(tp)) - { - } + template<typename Rep, int Y, int M, int D, int H, int N, int S, typename Ratio> + datetime(datetime_type type, std::chrono::time_point<util::arbitrary_clock<Rep, Y, M, D, H, N, S, Ratio> > tp) + : m_type(type) + , m_time_point(imgtool_clock::from_arbitrary_time_point(tp)) + { + } - datetime(datetime_type type, std::chrono::time_point<std::chrono::system_clock> tp); - datetime(datetime_type type, time_t t); - datetime(datetime_type type, const util::arbitrary_datetime &dt, bool clamp = true); - datetime(const datetime &that) = default; - datetime(datetime &&that) = default; + datetime(datetime_type type, std::chrono::time_point<std::chrono::system_clock> tp); + datetime(datetime_type type, time_t t); + datetime(datetime_type type, const util::arbitrary_datetime &dt, bool clamp = true); + datetime(const datetime &that) = default; + datetime(datetime &&that) = default; - // accessors - datetime_type type() const { return m_type; } - bool empty() const { return type() == datetime_type::NONE; } - std::chrono::time_point<imgtool_clock> time_point() const { return m_time_point; } + // accessors + datetime_type type() const { return m_type; } + bool empty() const { return type() == datetime_type::NONE; } + std::chrono::time_point<imgtool_clock> time_point() const { return m_time_point; } - // operators - datetime &operator =(const datetime &that) - { - m_type = that.m_type; - m_time_point = that.m_time_point; - return *this; - } + // operators + datetime &operator =(const datetime &that) + { + m_type = that.m_type; + m_time_point = that.m_time_point; + return *this; + } - // returns the current time - static datetime now(datetime_type type); + // returns the current time + static datetime now(datetime_type type); - // returns time structures - std::tm localtime() const; - std::tm gmtime() const; - time_t to_time_t() const; + // returns time structures + std::tm localtime() const; + std::tm gmtime() const; + time_t to_time_t() const; - private: - static imgtool_clock::duration s_gmt_offset; - datetime_type m_type; - std::chrono::time_point<imgtool_clock> m_time_point; +private: + static imgtool_clock::duration s_gmt_offset; + datetime_type m_type; + std::chrono::time_point<imgtool_clock> m_time_point; - static imgtool_clock::duration calculate_gmt_offset(); - }; + static imgtool_clock::duration calculate_gmt_offset(); }; -struct imgtool_dirent -{ - char filename[1024]; - char attr[64]; - uint64_t filesize; - - imgtool::datetime creation_time; - imgtool::datetime lastmodified_time; - imgtool::datetime lastaccess_time; - - char softlink[1024]; - char comment[256]; - /* flags */ - unsigned int eof : 1; - unsigned int corrupt : 1; - unsigned int directory : 1; - unsigned int hardlink : 1; -}; - -struct imgtool_chainent +struct chainent { uint8_t level; uint64_t block; }; -namespace imgtool +class fork_entry { - class fork_entry +public: + enum class type_t { - public: - enum class type_t - { - DATA, - RESOURCE, - ALT - }; - - fork_entry(uint64_t size, type_t type = type_t::DATA) - : m_size(size) - , m_type(type) - , m_name(default_name(type)) - { + DATA, + RESOURCE, + ALT + }; - } + fork_entry(uint64_t size, type_t type = type_t::DATA) + : m_size(size) + , m_type(type) + , m_name(default_name(type)) + { - fork_entry(uint64_t size, std::string &&name) - : m_size(size) - , m_type(fork_entry::type_t::ALT) - , m_name(std::move(name)) - { - } + } - fork_entry(const fork_entry &that) = default; - fork_entry(fork_entry &&that) = default; + fork_entry(uint64_t size, std::string &&name) + : m_size(size) + , m_type(fork_entry::type_t::ALT) + , m_name(std::move(name)) + { + } - uint64_t size() const { return m_size; } - type_t type() const { return m_type; } - const std::string &name() const { return m_name; } + fork_entry(const fork_entry &that) = default; + fork_entry(fork_entry &&that) = default; - private: - static std::string default_name(type_t type) + uint64_t size() const { return m_size; } + type_t type() const { return m_type; } + const std::string &name() const { return m_name; } + +private: + static std::string default_name(type_t type) + { + switch (type) { - switch (type) - { - case type_t::DATA: - return std::string(""); - case type_t::RESOURCE: - return std::string("RESOURCE_FORK"); - default: - throw false; - } + case type_t::DATA: + return std::string(""); + case type_t::RESOURCE: + return std::string("RESOURCE_FORK"); + default: + throw false; } + } - uint64_t m_size; - type_t m_type; - std::string m_name; - }; -} + uint64_t m_size; + type_t m_type; + std::string m_name; +}; -struct imgtool_transfer_suggestion +struct transfer_suggestion { - imgtool_suggestion_viability_t viability; + suggestion_viability_t viability; filter_getinfoproc filter; const char *fork; const char *description; }; +} // namespace imgtool + +struct imgtool_dirent +{ + imgtool_dirent() + { + std::fill(std::begin(filename), std::end(filename), 0); + std::fill(std::begin(attr), std::end(attr), 0); + filesize = 0; + + std::fill(std::begin(softlink), std::end(softlink), 0); + std::fill(std::begin(comment), std::end(comment), 0); + + eof = corrupt = directory = hardlink = 0; + } + + char filename[1024]; + char attr[64]; + uint64_t filesize; + + imgtool::datetime creation_time; + imgtool::datetime lastmodified_time; + imgtool::datetime lastaccess_time; + + char softlink[1024]; + char comment[256]; + + /* flags */ + unsigned int eof : 1; + unsigned int corrupt : 1; + unsigned int directory : 1; + unsigned int hardlink : 1; +}; + enum { /* --- the following bits of info are returned as 64-bit signed integers --- */ @@ -407,8 +416,8 @@ union imgtoolinfo imgtoolerr_t (*set_attrs) (imgtool::partition &partition, const char *path, const uint32_t *attrs, const imgtool_attribute *values); imgtoolerr_t (*attr_name) (uint32_t attribute, const imgtool_attribute *attr, char *buffer, size_t buffer_len); imgtoolerr_t (*get_iconinfo) (imgtool::partition &partition, const char *path, imgtool_iconinfo *iconinfo); - imgtoolerr_t (*suggest_transfer) (imgtool::partition &partition, const char *path, imgtool_transfer_suggestion *suggestions, size_t suggestions_length); - imgtoolerr_t (*get_chain) (imgtool::partition &partition, const char *path, imgtool_chainent *chain, size_t chain_size); + imgtoolerr_t (*suggest_transfer) (imgtool::partition &partition, const char *path, imgtool::transfer_suggestion *suggestions, size_t suggestions_length); + imgtoolerr_t (*get_chain) (imgtool::partition &partition, const char *path, imgtool::chainent *chain, size_t chain_size); imgtoolerr_t (*get_geometry) (imgtool::image &image, uint32_t *tracks, uint32_t *heads, uint32_t *sectors); imgtoolerr_t (*read_sector) (imgtool::image &image, uint32_t track, uint32_t head, uint32_t sector, std::vector<uint8_t> &buffer); imgtoolerr_t (*write_sector) (imgtool::image &image, uint32_t track, uint32_t head, uint32_t sector, const void *buffer, size_t len, int ddam); diff --git a/src/tools/imgtool/main.cpp b/src/tools/imgtool/main.cpp index 9777a8b35f8..ca38d7905cb 100644 --- a/src/tools/imgtool/main.cpp +++ b/src/tools/imgtool/main.cpp @@ -51,7 +51,7 @@ static void writeusage(std::wostream &output, bool write_word_usage, const struc // ---------------------------------------------------------------------- static int parse_options(int argc, char *argv[], int minunnamed, int maxunnamed, - util::option_resolution *resolution, filter_getinfoproc *filter, const char **fork) + util::option_resolution *resolution, imgtool::filter_getinfoproc *filter, const char **fork) { int i; int lastunnamed = 0; @@ -242,7 +242,6 @@ static int cmd_dir(const struct command *c, int argc, char *argv[]) if (err) goto done; - memset(&ent, 0, sizeof(ent)); last_modified[0] = '\0'; total_count = 0; total_size = 0; @@ -286,7 +285,7 @@ static int cmd_dir(const struct command *c, int argc, char *argv[]) total_count++; total_size += ent.filesize; - memset(&ent, 0, sizeof(ent)); + ent = imgtool_dirent(); } freespace_err = partition->get_free_space(freespace); @@ -317,7 +316,7 @@ static int cmd_get(const struct command *c, int argc, char *argv[]) const char *filename; char *new_filename; int unnamedargs = 0; - filter_getinfoproc filter; + imgtool::filter_getinfoproc filter; const char *fork; int partition_index = 0; @@ -354,12 +353,11 @@ done: static int cmd_put(const struct command *c, int argc, char *argv[]) { imgtoolerr_t err = IMGTOOLERR_SUCCESS; - int i; imgtool::image::ptr image; imgtool::partition::ptr partition; const char *filename = nullptr; int unnamedargs; - filter_getinfoproc filter; + imgtool::filter_getinfoproc filter; const imgtool_module *module; std::unique_ptr<util::option_resolution> resolution; const char *fork; @@ -417,7 +415,7 @@ static int cmd_put(const struct command *c, int argc, char *argv[]) filename_count = unnamedargs - 3; /* loop through the filenames, and put them */ - for (i = 0; i < filename_count; i++) + for (int i = 0; i < filename_count; i++) { filename = filename_list[i]; util::stream_format(std::wcout, L"Putting file '%s'...\n", wstring_from_utf8(filename)); @@ -441,7 +439,7 @@ static int cmd_getall(const struct command *c, int argc, char *argv[]) imgtool::partition::ptr partition; imgtool::directory::ptr imgenum; imgtool_dirent ent; - filter_getinfoproc filter; + imgtool::filter_getinfoproc filter; int unnamedargs; const char *path = ""; int arg; @@ -469,8 +467,6 @@ static int cmd_getall(const struct command *c, int argc, char *argv[]) if (err) goto done; - memset(&ent, 0, sizeof(ent)); - while (((err = imgenum->get_next(ent)) == 0) && !ent.eof) { util::stream_format(std::wcout, L"Retrieving %s (%u bytes)\n", wstring_from_utf8(ent.filename), (unsigned int)ent.filesize); diff --git a/src/tools/imgtool/modules/amiga.cpp b/src/tools/imgtool/modules/amiga.cpp index 2d9a793c54d..fcf1bd779a6 100644 --- a/src/tools/imgtool/modules/amiga.cpp +++ b/src/tools/imgtool/modules/amiga.cpp @@ -1712,7 +1712,7 @@ static imgtoolerr_t write_file_ext_data(imgtool::image &img, int block, int *fil static imgtoolerr_t clear_file_ext_data(imgtool::image &img, int block, int *filesize) { - return walk_file_ext_data(img, block, filesize, NULL, false); + return walk_file_ext_data(img, block, filesize, nullptr, false); } @@ -2340,7 +2340,7 @@ static imgtoolerr_t amiga_image_geticoninfo(imgtool::partition &partition, const } -static imgtoolerr_t amiga_image_suggesttransfer(imgtool::partition &partition, const char *fname, imgtool_transfer_suggestion *suggestions, size_t suggestions_length) +static imgtoolerr_t amiga_image_suggesttransfer(imgtool::partition &partition, const char *fname, imgtool::transfer_suggestion *suggestions, size_t suggestions_length) { return IMGTOOLERR_UNIMPLEMENTED; } @@ -2387,7 +2387,7 @@ void amiga_floppy_get_info(const imgtool_class *imgclass, uint32_t state, union case IMGTOOLINFO_INT_SUPPORTS_LASTMODIFIED_TIME: info->i = 1; break; case IMGTOOLINFO_INT_PATH_SEPARATOR: info->i = '/'; break; - /* --- the following bits of info are returned as NULL-terminated strings --- */ + /* --- the following bits of info are returned as NUL-terminated strings --- */ case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "amiga_floppy"); break; case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "Amiga floppy disk image (OFS/FFS format)"); break; case IMGTOOLINFO_STR_FILE_EXTENSIONS: strcpy(info->s = imgtool_temp_str(), "adf"); break; diff --git a/src/tools/imgtool/modules/bml3.cpp b/src/tools/imgtool/modules/bml3.cpp index 68c6b8d51ca..8c465032f28 100644 --- a/src/tools/imgtool/modules/bml3.cpp +++ b/src/tools/imgtool/modules/bml3.cpp @@ -840,7 +840,7 @@ static imgtoolerr_t bml3_diskimage_deletefile(imgtool::partition &partition, con -static imgtoolerr_t bml3_diskimage_suggesttransfer(imgtool::partition &partition, const char *fname, imgtool_transfer_suggestion *suggestions, size_t suggestions_length) +static imgtoolerr_t bml3_diskimage_suggesttransfer(imgtool::partition &partition, const char *fname, imgtool::transfer_suggestion *suggestions, size_t suggestions_length) { imgtoolerr_t err; imgtool::image &image(partition.image()); @@ -856,27 +856,27 @@ static imgtoolerr_t bml3_diskimage_suggesttransfer(imgtool::partition &partition if (ent.asciiflag == 0xFF) { /* ASCII file */ - suggestions[0].viability = SUGGESTION_RECOMMENDED; + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; suggestions[0].filter = filter_eoln_getinfo; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = NULL; + suggestions[1].viability = imgtool::SUGGESTION_POSSIBLE; + suggestions[1].filter = nullptr; } else if (ent.ftype == 0) { /* tokenized BASIC file */ - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; - suggestions[1].viability = SUGGESTION_POSSIBLE; + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; + suggestions[0].filter = nullptr; + suggestions[1].viability = imgtool::SUGGESTION_POSSIBLE; suggestions[1].filter = filter_bml3bas_getinfo; } } else { - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; - suggestions[1].viability = SUGGESTION_POSSIBLE; + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; + suggestions[0].filter = nullptr; + suggestions[1].viability = imgtool::SUGGESTION_POSSIBLE; suggestions[1].filter = filter_eoln_getinfo; - suggestions[2].viability = SUGGESTION_POSSIBLE; + suggestions[2].viability = imgtool::SUGGESTION_POSSIBLE; suggestions[2].filter = filter_bml3bas_getinfo; } @@ -911,9 +911,9 @@ void bml3_get_info(const imgtool_class *imgclass, uint32_t state, union imgtooli /* --- the following bits of info are returned as 64-bit signed integers --- */ case IMGTOOLINFO_INT_PREFER_UCASE: info->i = 1; break; case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES: info->i = sizeof(bml3_diskinfo); break; - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(struct bml3_direnum); break; + case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(struct bml3_direnum); break; - /* --- the following bits of info are returned as NULL-terminated strings --- */ + /* --- the following bits of info are returned as NUL-terminated strings --- */ case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "bml3"); break; case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "Basic Master Level 3 format"); break; case IMGTOOLINFO_STR_FILE: strcpy(info->s = imgtool_temp_str(), __FILE__); break; diff --git a/src/tools/imgtool/modules/dgndos.cpp b/src/tools/imgtool/modules/dgndos.cpp index 147e8e8a6c7..692c010d057 100644 --- a/src/tools/imgtool/modules/dgndos.cpp +++ b/src/tools/imgtool/modules/dgndos.cpp @@ -1097,7 +1097,7 @@ static imgtoolerr_t dgndos_diskimage_writefile(imgtool::partition &partition, co return IMGTOOLERR_SUCCESS; } -static imgtoolerr_t dgndos_diskimage_suggesttransfer(imgtool::partition &partition, const char *fname, imgtool_transfer_suggestion *suggestions, size_t suggestions_length) +static imgtoolerr_t dgndos_diskimage_suggesttransfer(imgtool::partition &partition, const char *fname, imgtool::transfer_suggestion *suggestions, size_t suggestions_length) { floperr_t ferr; imgtoolerr_t err; @@ -1119,27 +1119,27 @@ static imgtoolerr_t dgndos_diskimage_suggesttransfer(imgtool::partition &partiti if (strcmp(ent.block.header.filename+8,"DAT") == 0) { /* ASCII file */ - suggestions[0].viability = SUGGESTION_RECOMMENDED; + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; suggestions[0].filter = filter_eoln_getinfo; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = NULL; + suggestions[1].viability = imgtool::SUGGESTION_POSSIBLE; + suggestions[1].filter = nullptr; } else if (strcmp(ent.block.header.filename+8,"BAS") == 0) { /* tokenized BASIC file */ - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; - suggestions[1].viability = SUGGESTION_POSSIBLE; + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; + suggestions[0].filter = nullptr; + suggestions[1].viability = imgtool::SUGGESTION_POSSIBLE; suggestions[1].filter = filter_dragonbas_getinfo; } } else { - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; - suggestions[1].viability = SUGGESTION_POSSIBLE; + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; + suggestions[0].filter = nullptr; + suggestions[1].viability = imgtool::SUGGESTION_POSSIBLE; suggestions[1].filter = filter_eoln_getinfo; - suggestions[2].viability = SUGGESTION_POSSIBLE; + suggestions[2].viability = imgtool::SUGGESTION_POSSIBLE; suggestions[2].filter = filter_dragonbas_getinfo; } @@ -1234,7 +1234,7 @@ void dgndos_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoo case IMGTOOLINFO_INT_PREFER_UCASE: info->i = 1; break; case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(struct dgndos_direnum); break; - /* --- the following bits of info are returned as NULL-terminated strings --- */ + /* --- the following bits of info are returned as NUL-terminated strings --- */ case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "dgndos"); break; case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "Dragon DOS format"); break; case IMGTOOLINFO_STR_FILE: strcpy(info->s = imgtool_temp_str(), __FILE__); break; diff --git a/src/tools/imgtool/modules/fat.cpp b/src/tools/imgtool/modules/fat.cpp index f61d073b5f8..d6611932c0d 100644 --- a/src/tools/imgtool/modules/fat.cpp +++ b/src/tools/imgtool/modules/fat.cpp @@ -140,6 +140,7 @@ #include "multibyte.h" #include "unicode.h" +#include <algorithm> #include <cctype> #include <cstdio> #include <ctime> @@ -179,6 +180,18 @@ struct fat_file struct fat_dirent { + fat_dirent() : + directory(0), + eof(0), + filesize(0), + first_cluster(0), + dirent_sector_index(0), + dirent_sector_offset(0) + { + std::fill(std::begin(long_filename), std::end(long_filename), 0); + std::fill(std::begin(short_filename), std::end(short_filename), 0); + } + char long_filename[512]; char short_filename[13]; unsigned int directory : 1; @@ -1273,15 +1286,16 @@ static uint32_t fat_setup_time(time_t ansi_time) -static imgtoolerr_t fat_read_dirent(imgtool::partition &partition, fat_file *file, - fat_dirent &ent, fat_freeentry_info *freeent) +static imgtoolerr_t fat_read_dirent( + imgtool::partition &partition, + fat_file *file, + fat_dirent &ent, + fat_freeentry_info *freeent) { imgtoolerr_t err; //const fat_partition_info *disk_info; uint8_t entry[FAT_DIRENT_SIZE]; size_t bytes_read; - int i, j; - char32_t ch; char16_t lfn_buf[512]; size_t lfn_len = 0; int lfn_lastentry = 0; @@ -1290,7 +1304,7 @@ static imgtoolerr_t fat_read_dirent(imgtool::partition &partition, fat_file *fil assert(file->directory); lfn_buf[0] = '\0'; - memset(&ent, 0, sizeof(ent)); + ent = fat_dirent(); //disk_info = fat_get_partition_info(partition); /* The first eight bytes of a FAT directory entry is a blank padded name @@ -1351,7 +1365,7 @@ static imgtoolerr_t fat_read_dirent(imgtool::partition &partition, fat_file *fil } } } - while((entry[0] == 0x2E) || (entry[0] == 0xE5) || (entry[11] == 0x0F)); + while ((entry[0] == 0x2E) || (entry[0] == 0xE5) || (entry[11] == 0x0F)); /* no more directory entries? */ if (entry[0] == '\0') @@ -1369,14 +1383,14 @@ static imgtoolerr_t fat_read_dirent(imgtool::partition &partition, fat_file *fil /* only use the LFN if the checksum passes */ if (lfn_checksum == fat_calc_filename_checksum(entry)) { - i = 0; - j = 0; + int i = 0, j = 0; + char32_t ch; do { i += uchar_from_utf16(&ch, &lfn_buf[i], std::size(lfn_buf) - i); j += utf8_from_uchar(&ent.long_filename[j], std::size(ent.long_filename) - j, ch); } - while(ch != 0); + while (ch != 0); } } diff --git a/src/tools/imgtool/modules/hp9845_tape.cpp b/src/tools/imgtool/modules/hp9845_tape.cpp index 8398f63bdce..26cb2f4eb1c 100644 --- a/src/tools/imgtool/modules/hp9845_tape.cpp +++ b/src/tools/imgtool/modules/hp9845_tape.cpp @@ -1514,7 +1514,7 @@ static imgtoolerr_t hp9845data_write_file(imgtool::partition &partition, const c return res; } -void filter_hp9845data_getinfo(uint32_t state, union filterinfo *info) +void filter_hp9845data_getinfo(uint32_t state, imgtool::filterinfo *info) { switch (state) { case FILTINFO_PTR_READFILE: diff --git a/src/tools/imgtool/modules/rsdos.cpp b/src/tools/imgtool/modules/rsdos.cpp index c07e215f2da..b4924338309 100644 --- a/src/tools/imgtool/modules/rsdos.cpp +++ b/src/tools/imgtool/modules/rsdos.cpp @@ -573,7 +573,7 @@ static imgtoolerr_t rsdos_diskimage_deletefile(imgtool::partition &partition, co // rsdos_diskimage_suggesttransfer //------------------------------------------------- -static imgtoolerr_t rsdos_diskimage_suggesttransfer(imgtool::partition &partition, const char *fname, imgtool_transfer_suggestion *suggestions, size_t suggestions_length) +static imgtoolerr_t rsdos_diskimage_suggesttransfer(imgtool::partition &partition, const char *fname, imgtool::transfer_suggestion *suggestions, size_t suggestions_length) { imgtoolerr_t err; imgtool::image &image(partition.image()); @@ -589,27 +589,27 @@ static imgtoolerr_t rsdos_diskimage_suggesttransfer(imgtool::partition &partitio if (ent.asciiflag == (char) 0xFF) { /* ASCII file */ - suggestions[0].viability = SUGGESTION_RECOMMENDED; + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; suggestions[0].filter = filter_eoln_getinfo; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = NULL; + suggestions[1].viability = imgtool::SUGGESTION_POSSIBLE; + suggestions[1].filter = nullptr; } else if (ent.ftype == 0) { /* tokenized BASIC file */ - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; - suggestions[1].viability = SUGGESTION_POSSIBLE; + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; + suggestions[0].filter = nullptr; + suggestions[1].viability = imgtool::SUGGESTION_POSSIBLE; suggestions[1].filter = filter_cocobas_getinfo; } } else { - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; - suggestions[1].viability = SUGGESTION_POSSIBLE; + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; + suggestions[0].filter = nullptr; + suggestions[1].viability = imgtool::SUGGESTION_POSSIBLE; suggestions[1].filter = filter_eoln_getinfo; - suggestions[2].viability = SUGGESTION_POSSIBLE; + suggestions[2].viability = imgtool::SUGGESTION_POSSIBLE; suggestions[2].filter = filter_cocobas_getinfo; } @@ -645,7 +645,7 @@ void rsdos_get_info(const imgtool_class *imgclass, uint32_t state, union imgtool case IMGTOOLINFO_INT_PREFER_UCASE: info->i = 1; break; case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(struct rsdos_direnum); break; - /* --- the following bits of info are returned as NULL-terminated strings --- */ + /* --- the following bits of info are returned as NUL-terminated strings --- */ case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "rsdos"); break; case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "RS-DOS format"); break; case IMGTOOLINFO_STR_FILE: strcpy(info->s = imgtool_temp_str(), __FILE__); break; diff --git a/src/tools/imgtool/modules/thomson.cpp b/src/tools/imgtool/modules/thomson.cpp index 495436dbebb..1978e3720ba 100644 --- a/src/tools/imgtool/modules/thomson.cpp +++ b/src/tools/imgtool/modules/thomson.cpp @@ -1072,10 +1072,11 @@ static imgtoolerr_t thom_write_file(imgtool::partition &part, return IMGTOOLERR_SUCCESS; } -static imgtoolerr_t thom_suggest_transfer(imgtool::partition &part, - const char *fname, - imgtool_transfer_suggestion *suggestions, - size_t suggestions_length) +static imgtoolerr_t thom_suggest_transfer( + imgtool::partition &part, + const char *fname, + imgtool::transfer_suggestion *suggestions, + size_t suggestions_length) { int head = *( (int*) part.extra_bytes() ); imgtool::image &img(part.image()); @@ -1086,30 +1087,30 @@ static imgtoolerr_t thom_suggest_transfer(imgtool::partition &part, if ( suggestions_length < 1 ) return IMGTOOLERR_SUCCESS; if ( fname ) { - if ( ! thom_find_dirent( f, head, fname, &d ) ) - return IMGTOOLERR_FILENOTFOUND; - if ( d.ftype == 0 && d.format == 0 ) is_basic = 1; + if ( ! thom_find_dirent( f, head, fname, &d ) ) + return IMGTOOLERR_FILENOTFOUND; + if ( d.ftype == 0 && d.format == 0 ) is_basic = 1; } if ( is_basic ) { - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = filter_thombas128_getinfo; - if ( suggestions_length >= 2 ) { - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = filter_thombas7_getinfo; - } - if ( suggestions_length >= 3 ) { - suggestions[2].viability = SUGGESTION_POSSIBLE; - suggestions[2].filter = filter_thombas5_getinfo; - } - if ( suggestions_length >= 4 ) { - suggestions[3].viability = SUGGESTION_POSSIBLE; - suggestions[3].filter = NULL; - } + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; + suggestions[0].filter = filter_thombas128_getinfo; + if ( suggestions_length >= 2 ) { + suggestions[1].viability = imgtool::SUGGESTION_POSSIBLE; + suggestions[1].filter = filter_thombas7_getinfo; + } + if ( suggestions_length >= 3 ) { + suggestions[2].viability = imgtool::SUGGESTION_POSSIBLE; + suggestions[2].filter = filter_thombas5_getinfo; + } + if ( suggestions_length >= 4 ) { + suggestions[3].viability = imgtool::SUGGESTION_POSSIBLE; + suggestions[3].filter = nullptr; + } } else { - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; + suggestions[0].filter = nullptr; } return IMGTOOLERR_SUCCESS; @@ -1211,12 +1212,12 @@ static const char *const thombas7[2][128] = { /* MO5: some keywords ar missing; DOS and TUNE are added */ static const char *const thombas5[2][128] = { { /* statements */ - "END", "FOR", "NEXT", "DATA", "DIM", "READ", NULL, "GO", "RUN", "IF", + "END", "FOR", "NEXT", "DATA", "DIM", "READ", nullptr, "GO", "RUN", "IF", "RESTORE", "RETURN", "REM", "'", "STOP", "ELSE", "TRON", "TROFF", "DEFSTR", - "DEFINT", "DEFSNG", NULL, "ON", "TUNE", "ERROR", "RESUME", "AUTO", + "DEFINT", "DEFSNG", nullptr, "ON", "TUNE", "ERROR", "RESUME", "AUTO", "DELETE", "LOCATE", "CLS", "CONSOLE", "PSET", "MOTOR", "SKIP", "EXEC", - "BEEP", "COLOR", "LINE", "BOX", NULL, "ATTRB", "DEF", "POKE", "PRINT", - "CONT", "LIST", "CLEAR", "DOS", NULL, "NEW", "SAVE", "LOAD", "MERGE", + "BEEP", "COLOR", "LINE", "BOX", nullptr, "ATTRB", "DEF", "POKE", "PRINT", + "CONT", "LIST", "CLEAR", "DOS", nullptr, "NEW", "SAVE", "LOAD", "MERGE", "OPEN", "CLOSE", "INPEN", "PEN", "PLAY", "TAB(", "TO", "SUB", "FN", "SPC(", "USING", "USR", "ERL", "ERR", "OFF", "THEN", "NOT", "STEP", "+", "-", "*", "/", "^", "AND", "OR", "XOR", "EQV", "IMP", "MOD", "@", @@ -1229,8 +1230,8 @@ static const char *const thombas5[2][128] = { }, { /* functions: 0xff prefix */ "SGN", "INT", "ABS", "FRE", "SQR", "LOG", "EXP", "COS", "SIN", - "TAN", "PEEK", "LEN", "STR$", "VAL", "ASC", "CHR$", "EOF", "CINT", NULL, - NULL, "FIX", "HEX$", NULL, "STICK", "STRIG", "GR$", "LEFT$", "RIGHT$", + "TAN", "PEEK", "LEN", "STR$", "VAL", "ASC", "CHR$", "EOF", "CINT", nullptr, + nullptr, "FIX", "HEX$", nullptr, "STICK", "STRIG", "GR$", "LEFT$", "RIGHT$", "MID$", "INSTR", "VARPTR", "RND", "INKEY$", "INPUT", "CSRLIN", "POINT", "SCREEN", "POS", "PTRIG", /* DOS specific */ @@ -1373,7 +1374,7 @@ static imgtoolerr_t thomcrypt_write_file(imgtool::partition &part, } } -void filter_thomcrypt_getinfo(uint32_t state, union filterinfo *info) +void filter_thomcrypt_getinfo(uint32_t state, imgtool::filterinfo *info) { switch(state) { case FILTINFO_STR_NAME: @@ -1601,16 +1602,14 @@ struct { { "\xc3\xa7", "\x16" "Kc" }, { "\xc3\x87", "\x16" "KC" }, - { NULL, NULL } + { nullptr, nullptr } }; static bool thom_basic_is_specialchar(const char *buf, int *pos, const char **thom) { - int i; - - for (i = 0; special_chars[i].utf8 != NULL; i++) + for (int i = 0; special_chars[i].utf8 != nullptr; i++) { if (!strncmp(&buf[*pos], special_chars[i].utf8, strlen(special_chars[i].utf8))) { @@ -1875,32 +1874,33 @@ static imgtoolerr_t thom_basic_write_file(imgtool::partition &partition, const char *fork, \ imgtool::stream &dst) \ { \ - return thom_basic_read_file( part, name, fork, dst, short ); \ + return thom_basic_read_file( part, name, fork, dst, short ); \ } \ - static imgtoolerr_t short##_write_file(imgtool::partition &part, \ - const char *name, \ - const char *fork, \ - imgtool::stream &src, \ - util::option_resolution *opts) \ + static imgtoolerr_t short##_write_file( \ + imgtool::partition &part, \ + const char *name, \ + const char *fork, \ + imgtool::stream &src, \ + util::option_resolution *opts) \ { \ - return thom_basic_write_file( part, name, fork, src, opts, short ); \ + return thom_basic_write_file( part, name, fork, src, opts, short ); \ } \ - void filter_##short##_getinfo(uint32_t state, union filterinfo *info) \ + void filter_##short##_getinfo(uint32_t state, imgtool::filterinfo *info) \ { \ switch(state) \ { \ case FILTINFO_STR_NAME: \ - info->s = #short; \ - break; \ + info->s = #short; \ + break; \ case FILTINFO_STR_HUMANNAME: \ - info->s = long; \ - break; \ + info->s = long; \ + break; \ case FILTINFO_PTR_READFILE: \ - info->read_file = short##_read_file; \ - break; \ + info->read_file = short##_read_file; \ + break; \ case FILTINFO_PTR_WRITEFILE: \ - info->write_file = short##_write_file; \ - break; \ + info->write_file = short##_write_file; \ + break; \ } \ } @@ -1946,57 +1946,57 @@ static void thom_basic_get_info(const imgtool_class *clas, { switch ( param ) { case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES: - info->i = sizeof(thom_floppy); break; + info->i = sizeof(thom_floppy); break; case IMGTOOLINFO_INT_PARTITION_EXTRA_BYTES: - info->i = sizeof(int); break; + info->i = sizeof(int); break; case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: - info->i = sizeof(int); break; + info->i = sizeof(int); break; case IMGTOOLINFO_INT_SUPPORTS_CREATION_TIME: case IMGTOOLINFO_INT_PREFER_UCASE: - info->i = 1; break; + info->i = 1; break; case IMGTOOLINFO_INT_PATH_SEPARATOR: - info->i = 0; break; + info->i = 0; break; case IMGTOOLINFO_STR_FILE: - strcpy( info->s = imgtool_temp_str(), __FILE__ ); break; + strcpy( info->s = imgtool_temp_str(), __FILE__ ); break; case IMGTOOLINFO_STR_NAME: - strcpy( info->s = imgtool_temp_str(), "thom" ); break; + strcpy( info->s = imgtool_temp_str(), "thom" ); break; case IMGTOOLINFO_STR_DESCRIPTION: - strcpy( info->s = imgtool_temp_str(), "Thomson BASIC filesystem" ); - break; + strcpy( info->s = imgtool_temp_str(), "Thomson BASIC filesystem" ); + break; case IMGTOOLINFO_PTR_CREATE: - info->create = thom_create; break; + info->create = thom_create; break; case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE: - info->createimage_optguide = &thom_createimage_optguide; break; + info->createimage_optguide = &thom_createimage_optguide; break; case IMGTOOLINFO_PTR_BEGIN_ENUM: - info->begin_enum = thom_begin_enum; break; + info->begin_enum = thom_begin_enum; break; case IMGTOOLINFO_PTR_NEXT_ENUM: - info->next_enum = thom_next_enum; break; + info->next_enum = thom_next_enum; break; case IMGTOOLINFO_PTR_READ_FILE: - info->read_file = thom_read_file; break; + info->read_file = thom_read_file; break; case IMGTOOLINFO_PTR_WRITE_FILE: - info->write_file = thom_write_file; break; + info->write_file = thom_write_file; break; case IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE: - info->writefile_optguide = &thom_writefile_optguide; break; + info->writefile_optguide = &thom_writefile_optguide; break; case IMGTOOLINFO_STR_WRITEFILE_OPTSPEC: - strcpy( info->s = imgtool_temp_str(), "T[0]-4;F[0]-2;C" ); break; + strcpy( info->s = imgtool_temp_str(), "T[0]-4;F[0]-2;C" ); break; case IMGTOOLINFO_PTR_SUGGEST_TRANSFER: - info->suggest_transfer = thom_suggest_transfer; break; + info->suggest_transfer = thom_suggest_transfer; break; case IMGTOOLINFO_PTR_DELETE_FILE: - info->delete_file = thom_delete_file; break; + info->delete_file = thom_delete_file; break; case IMGTOOLINFO_PTR_FREE_SPACE: - info->free_space = thom_free_space; break; + info->free_space = thom_free_space; break; case IMGTOOLINFO_PTR_GET_GEOMETRY: - info->get_geometry = thom_get_geometry; break; + info->get_geometry = thom_get_geometry; break; case IMGTOOLINFO_PTR_INFO: - info->info = thom_info; break; + info->info = thom_info; break; case IMGTOOLINFO_PTR_READ_SECTOR: - info->read_sector = thom_read_sector; break; + info->read_sector = thom_read_sector; break; case IMGTOOLINFO_PTR_WRITE_SECTOR: - info->write_sector = thom_write_sector; break; + info->write_sector = thom_write_sector; break; case IMGTOOLINFO_PTR_LIST_PARTITIONS: - info->list_partitions = thom_list_partitions; break; + info->list_partitions = thom_list_partitions; break; case IMGTOOLINFO_PTR_OPEN_PARTITION: - info->open_partition = thom_open_partition; break; + info->open_partition = thom_open_partition; break; } } @@ -2006,21 +2006,21 @@ void thom_fd_basic_get_info(const imgtool_class *clas, { switch ( param ) { case IMGTOOLINFO_STR_NAME: - strcpy( info->s = imgtool_temp_str(), "thom_fd" ); break; + strcpy( info->s = imgtool_temp_str(), "thom_fd" ); break; case IMGTOOLINFO_STR_DESCRIPTION: - strcpy( info->s = imgtool_temp_str(), - "Thomson .fd disk image, BASIC format" ); - break; + strcpy( info->s = imgtool_temp_str(), + "Thomson .fd disk image, BASIC format" ); + break; case IMGTOOLINFO_STR_FILE_EXTENSIONS: - strcpy( info->s = imgtool_temp_str(), "fd" ); break; + strcpy( info->s = imgtool_temp_str(), "fd" ); break; case IMGTOOLINFO_PTR_OPEN: - info->open = thom_open_fd_qd; break; + info->open = thom_open_fd_qd; break; case IMGTOOLINFO_PTR_CLOSE: - info->close = thom_close_fd_qd; break; + info->close = thom_close_fd_qd; break; case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC: - strcpy( info->s = imgtool_temp_str(), "H[1]-2;T40/[80];D0-[1];N" ); break; + strcpy( info->s = imgtool_temp_str(), "H[1]-2;T40/[80];D0-[1];N" ); break; default: - thom_basic_get_info( clas, param, info ); + thom_basic_get_info( clas, param, info ); } } @@ -2030,21 +2030,21 @@ void thom_qd_basic_get_info(const imgtool_class *clas, { switch ( param ) { case IMGTOOLINFO_STR_NAME: - strcpy( info->s = imgtool_temp_str(), "thom_qd" ); break; + strcpy( info->s = imgtool_temp_str(), "thom_qd" ); break; case IMGTOOLINFO_STR_DESCRIPTION: - strcpy( info->s = imgtool_temp_str(), - "Thomson .qd disk image, BASIC format" ); - break; + strcpy( info->s = imgtool_temp_str(), + "Thomson .qd disk image, BASIC format" ); + break; case IMGTOOLINFO_STR_FILE_EXTENSIONS: - strcpy( info->s = imgtool_temp_str(), "qd" ); break; + strcpy( info->s = imgtool_temp_str(), "qd" ); break; case IMGTOOLINFO_PTR_OPEN: - info->open = thom_open_fd_qd; break; + info->open = thom_open_fd_qd; break; case IMGTOOLINFO_PTR_CLOSE: - info->close = thom_close_fd_qd; break; + info->close = thom_close_fd_qd; break; case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC: - strcpy( info->s = imgtool_temp_str(), "H[1]-2;T[25];D[0];N" ); break; + strcpy( info->s = imgtool_temp_str(), "H[1]-2;T[25];D[0];N" ); break; default: - thom_basic_get_info( clas, param, info ); + thom_basic_get_info( clas, param, info ); } } @@ -2054,20 +2054,20 @@ void thom_sap_basic_get_info(const imgtool_class *clas, { switch ( param ) { case IMGTOOLINFO_STR_NAME: - strcpy( info->s = imgtool_temp_str(), "thom_sap" ); break; + strcpy( info->s = imgtool_temp_str(), "thom_sap" ); break; case IMGTOOLINFO_STR_DESCRIPTION: - strcpy( info->s = imgtool_temp_str(), - "Thomson .sap disk image, BASIC format" ); - break; + strcpy( info->s = imgtool_temp_str(), + "Thomson .sap disk image, BASIC format" ); + break; case IMGTOOLINFO_STR_FILE_EXTENSIONS: - strcpy( info->s = imgtool_temp_str(), "sap" ); break; + strcpy( info->s = imgtool_temp_str(), "sap" ); break; case IMGTOOLINFO_PTR_OPEN: - info->open = thom_open_sap; break; + info->open = thom_open_sap; break; case IMGTOOLINFO_PTR_CLOSE: - info->close = thom_close_sap; break; + info->close = thom_close_sap; break; case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC: - strcpy( info->s = imgtool_temp_str(), "H[1];T40/[80];D0-[1];N" ); break; + strcpy( info->s = imgtool_temp_str(), "H[1];T40/[80];D0-[1];N" ); break; default: - thom_basic_get_info( clas, param, info ); + thom_basic_get_info( clas, param, info ); } } diff --git a/src/tools/imgtool/modules/vzdos.cpp b/src/tools/imgtool/modules/vzdos.cpp index 0005c0973cf..b7dee751434 100644 --- a/src/tools/imgtool/modules/vzdos.cpp +++ b/src/tools/imgtool/modules/vzdos.cpp @@ -19,6 +19,7 @@ #include "multibyte.h" #include "opresolv.h" +#include <algorithm> #include <cmath> #include <cstdio> #include <cstdlib> @@ -51,20 +52,21 @@ as track map, with one bit for each sector used. /* vzdos directry entry */ struct vzdos_dirent { - char ftype; - char delimitor; - char fname[8]; + struct { + char ftype; + char delimitor; + char fname[8]; + } node; uint8_t start_track; uint8_t start_sector; uint16_t start_address; uint16_t end_address; - vzdos_dirent() + vzdos_dirent() : + start_track(0), start_sector(0), + start_address(0), end_address(0) { - ftype = delimitor = '\0'; - fname[0] = '\0'; - start_track = start_sector = 0; - start_address = end_address = 0; + memset(&node, 0, sizeof(node)); } }; @@ -160,8 +162,7 @@ static imgtoolerr_t vzdos_write_sector_data(imgtool::image &img, int track, int static imgtoolerr_t vzdos_clear_sector(imgtool::image &img, int track, int sector) { uint8_t data[DATA_SIZE + 2]; - - memset(data, 0x00, sizeof(data)); + std::fill(std::begin(data), std::end(data), 0x00); return vzdos_write_sector_data(img, track, sector, data); } @@ -169,21 +170,21 @@ static imgtoolerr_t vzdos_clear_sector(imgtool::image &img, int track, int secto /* return a directory entry for an index */ static imgtoolerr_t vzdos_get_dirent(imgtool::image &img, int index, vzdos_dirent *ent) { - int ret, entry; uint8_t buffer[DATA_SIZE + 2]; - ret = vzdos_read_sector_data(img, 0, (int) index / 8, buffer); - if (ret) return (imgtoolerr_t)ret; + imgtoolerr_t const ret = vzdos_read_sector_data(img, 0, int(index) / 8, buffer); + if (IMGTOOLERR_SUCCESS != ret) + return ret; - entry = ((index % 8) * sizeof(vzdos_dirent)); + int const entry = ((index % 8) * sizeof(vzdos_dirent)); - memcpy(ent, &buffer[entry], 10); + memcpy(&ent->node, &buffer[entry], 10); ent->start_track = buffer[entry + 10]; ent->start_sector = buffer[entry + 11]; ent->start_address = get_u16le(&buffer[entry + 12]); ent->end_address = get_u16le(&buffer[entry + 14]); - if (ent->ftype == 0x00) + if (ent->node.ftype == 0x00) return IMGTOOLERR_FILENOTFOUND; /* check values */ @@ -224,20 +225,12 @@ static imgtoolerr_t vzdos_set_dirent(imgtool::image &img, int index, vzdos_diren /* clear a directory entry */ static imgtoolerr_t vzdos_clear_dirent(imgtool::image &img, int index) { - int ret; vzdos_dirent entry; - - memset(&entry, 0x00, sizeof(vzdos_dirent)); - - ret = vzdos_set_dirent(img, index, entry); - if (ret) return (imgtoolerr_t)ret; - - return IMGTOOLERR_SUCCESS; + return vzdos_set_dirent(img, index, entry); } /* search the index for a directory entry */ static imgtoolerr_t vzdos_searchentry(imgtool::image &image, const char *fname, int *entry) { - int i, len, ret; vzdos_dirent ent; char filename[9]; @@ -249,23 +242,23 @@ static imgtoolerr_t vzdos_searchentry(imgtool::image &image, const char *fname, *entry = -1; - for (i = 0; i < MAX_DIRENTS; i++) { - ret = vzdos_get_dirent(image, i, &ent); - if (ret) return (imgtoolerr_t)ret; + for (int i = 0; i < MAX_DIRENTS; i++) { + imgtoolerr_t const ret = vzdos_get_dirent(image, i, &ent); + if (IMGTOOLERR_SUCCESS != ret) + return ret; - len = vzdos_get_fname_len(ent.fname) + 1; + int const len = vzdos_get_fname_len(ent.node.fname) + 1; if (strlen(fname) != len) continue; - memset(filename, 0x00, sizeof(filename)); - memcpy(filename, ent.fname, len); + std::fill(std::begin(filename), std::end(filename), 0x00); + memcpy(filename, ent.node.fname, len); if (!core_stricmp(fname, filename)) { *entry = i; break; } - } if (*entry == -1) @@ -362,7 +355,6 @@ static imgtoolerr_t vzdos_free_trackmap(imgtool::image &img, int *track, int *se static imgtoolerr_t vzdos_write_formatted_sector(imgtool::image &img, int track, int sector) { - int ret; uint8_t sector_data[DATA_SIZE + 4 + 24]; static const uint8_t sector_header[24] = { @@ -371,15 +363,16 @@ static imgtoolerr_t vzdos_write_formatted_sector(imgtool::image &img, int track, 0x80, 0x80, 0x80, 0x00, 0xC3, 0x18, 0xE7, 0xFE }; - memset(sector_data, 0x00, sizeof(sector_data)); + std::fill(std::begin(sector_data), std::end(sector_data), 0x00); memcpy(sector_data, sector_header, sizeof(sector_header)); sector_data[10] = (uint8_t) track; /* current track */ sector_data[11] = (uint8_t) sector; /* current sector */ sector_data[12] = (uint8_t) track + sector; /* checksum-8 */ - ret = floppy_write_sector(imgtool_floppy(img), 0, track, sector_order[sector], 0, sector_data, sizeof(sector_data), 0); /* TODO: pass ddam argument from imgtool */ - if (ret) return (imgtoolerr_t)ret; + floperr_t const ret = floppy_write_sector(imgtool_floppy(img), 0, track, sector_order[sector], 0, sector_data, sizeof(sector_data), 0); /* TODO: pass ddam argument from imgtool */ + if (FLOPPY_ERROR_SUCCESS != ret) + return IMGTOOLERR_WRITEERROR; return IMGTOOLERR_SUCCESS; } @@ -427,15 +420,15 @@ static imgtoolerr_t vzdos_diskimage_nextenum(imgtool::directory &enumeration, im /* kill trailing spaces */ for (len = 7; len > 0; len--) { - if (dirent.fname[len] != 0x20) { + if (dirent.node.fname[len] != 0x20) { break; } } - memcpy(ent.filename, &dirent.fname, len + 1); + memcpy(ent.filename, &dirent.node.fname, len + 1); ent.filesize = dirent.end_address - dirent.start_address; - switch (dirent.ftype) + switch (dirent.node.ftype) { case 0x01: type = "Deleted"; break; case 'T': type = "Basic"; break; @@ -620,8 +613,8 @@ static imgtoolerr_t vzdos_writefile(imgtool::partition &partition, int offset, i return IMGTOOLERR_READONLY; /* check for already existing filename -> overwrite */ - strcpy(filename, entry->fname); - filename[vzdos_get_fname_len(entry->fname) + 1] = 0x00; + strcpy(filename, entry->node.fname); + filename[vzdos_get_fname_len(entry->node.fname) + 1] = 0x00; ret = vzdos_get_dirent_fname(img, filename, &temp_entry); if (!ret) { /* file already exists, delete it */ @@ -705,8 +698,6 @@ static imgtoolerr_t vzdos_writefile(imgtool::partition &partition, int offset, i /* create a new file or overwrite a file */ static imgtoolerr_t vzdos_diskimage_writefile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &sourcef, util::option_resolution *opts) { - imgtoolerr_t ret; - int ftype; vzdos_dirent entry; /* TODO: check for leading spaces and strip */ @@ -714,37 +705,34 @@ static imgtoolerr_t vzdos_diskimage_writefile(imgtool::partition &partition, con return IMGTOOLERR_BADFILENAME; /* prepare directory entry */ - ftype = opts->lookup_int('T'); + int const ftype = opts->lookup_int('T'); switch (ftype) { case 0: - entry.ftype = 'T'; + entry.node.ftype = 'T'; entry.start_address = 31465; break; case 1: - entry.ftype = 'B'; + entry.node.ftype = 'B'; entry.start_address = 31465; /* ??? */ break; case 2: - entry.ftype = 'D'; + entry.node.ftype = 'D'; entry.start_address = 31465; /* ??? */ break; default: break; } - entry.delimitor = ':'; - memset(&entry.fname, 0x20, 8); /* pad with spaces */ - memcpy(&entry.fname, filename, strlen(filename)); + entry.node.delimitor = ':'; + memset(&entry.node.fname, 0x20, 8); /* pad with spaces */ + memcpy(&entry.node.fname, filename, strlen(filename)); /* write file to disk */ - ret = vzdos_writefile(partition, 0, sourcef, &entry); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; + return vzdos_writefile(partition, 0, sourcef, &entry); } -static imgtoolerr_t vzdos_diskimage_suggesttransfer(imgtool::partition &partition, const char *fname, imgtool_transfer_suggestion *suggestions, size_t suggestions_length) +static imgtoolerr_t vzdos_diskimage_suggesttransfer(imgtool::partition &partition, const char *fname, imgtool::transfer_suggestion *suggestions, size_t suggestions_length) { imgtoolerr_t ret; imgtool::image &image(partition.image()); @@ -754,37 +742,37 @@ static imgtoolerr_t vzdos_diskimage_suggesttransfer(imgtool::partition &partitio ret = vzdos_get_dirent_fname(image, fname, &entry); if (ret) return ret; - switch (entry.ftype) { + switch (entry.node.ftype) { case 'B': - suggestions[0].viability = SUGGESTION_RECOMMENDED; + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; suggestions[0].filter = filter_vzsnapshot_getinfo; suggestions[0].description = "VZ Snapshot"; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = NULL; + suggestions[1].viability = imgtool::SUGGESTION_POSSIBLE; + suggestions[1].filter = nullptr; suggestions[1].description = "Raw"; break; case 'T': - suggestions[0].viability = SUGGESTION_RECOMMENDED; + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; suggestions[0].filter = filter_vzsnapshot_getinfo; suggestions[0].description = "VZ Snapshot"; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = NULL; + suggestions[1].viability = imgtool::SUGGESTION_POSSIBLE; + suggestions[1].filter = nullptr; suggestions[1].description = "Raw"; - suggestions[2].viability = SUGGESTION_POSSIBLE; + suggestions[2].viability = imgtool::SUGGESTION_POSSIBLE; suggestions[2].filter = filter_vzbas_getinfo; suggestions[2].description = "Tokenized Basic"; break; default: - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; + suggestions[0].filter = nullptr; suggestions[0].description = "Raw"; } } else { - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; + suggestions[0].filter = nullptr; suggestions[0].description = "Raw"; - suggestions[1].viability = SUGGESTION_POSSIBLE; + suggestions[1].viability = imgtool::SUGGESTION_POSSIBLE; suggestions[1].filter = filter_vzsnapshot_getinfo; suggestions[1].description = "VZ Snapshot"; } @@ -827,7 +815,7 @@ static imgtoolerr_t vzsnapshot_readfile(imgtool::partition &partition, const cha header[1] = 'Z'; header[2] = 'F'; - switch (entry.ftype) { + switch (entry.node.ftype) { case 'B': header[3] = '1'; header[21] = 0xF1; @@ -842,7 +830,7 @@ static imgtoolerr_t vzsnapshot_readfile(imgtool::partition &partition, const cha } memset(header + 4, 0x00, 17); - memcpy(header + 4, entry.fname, vzdos_get_fname_len(entry.fname) + 1); + memcpy(header + 4, entry.node.fname, vzdos_get_fname_len(entry.node.fname) + 1); put_u16le(&header[22], entry.start_address); /* write header to file */ @@ -866,21 +854,21 @@ static imgtoolerr_t vzsnapshot_writefile(imgtool::partition &partition, const ch sourcef.read(header, sizeof(header)); /* prepare directory entry */ - entry.ftype = header[21] == 0xF1 ? 'B' : 'T'; - entry.delimitor = ':'; - entry.start_address = get_u16le(&header[22]); + entry.node.ftype = (header[21] == 0xF1) ? 'B' : 'T'; + entry.node.delimitor = ':'; + entry.start_address = get_u16le(&header[22]); /* filename from header or directly? */ fnameopt = opts->lookup_int('F'); if (fnameopt == 0) { - memcpy(&entry.fname, &header[4], 8); + memcpy(&entry.node.fname, &header[4], 8); } else { /* TODO: check for leading spaces and strip */ if (strlen(filename) > 8 || strlen(filename) < 1) return IMGTOOLERR_BADFILENAME; - memcpy(&entry.fname, filename, strlen(filename) - 3); + memcpy(&entry.node.fname, filename, strlen(filename) - 3); } /* write file to disk */ @@ -890,7 +878,7 @@ static imgtoolerr_t vzsnapshot_writefile(imgtool::partition &partition, const ch return IMGTOOLERR_SUCCESS; } -void filter_vzsnapshot_getinfo(uint32_t state, union filterinfo *info) +void filter_vzsnapshot_getinfo(uint32_t state, imgtool::filterinfo *info) { switch(state) { @@ -939,16 +927,16 @@ void vzdos_get_info(const imgtool_class *imgclass, uint32_t state, union imgtool case IMGTOOLINFO_INT_PREFER_UCASE: info->i = 1; break; case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(vz_iterator); break; - /* --- the following bits of info are returned as NULL-terminated strings --- */ + /* --- the following bits of info are returned as NUL-terminated strings --- */ case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "vzdos"); break; case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "VZ-DOS format"); break; case IMGTOOLINFO_STR_FILE: strcpy(info->s = imgtool_temp_str(), __FILE__); break; case IMGTOOLINFO_STR_WRITEFILE_OPTSPEC: strcpy(info->s = imgtool_temp_str(), "T[0]-2;F[0]-1"); break; - case IMGTOOLINFO_STR_EOLN: info->s = NULL; break; + case IMGTOOLINFO_STR_EOLN: info->s = nullptr; break; /* --- the following bits of info are returned as pointers to data or functions --- */ case IMGTOOLINFO_PTR_MAKE_CLASS: info->make_class = imgtool_floppy_make_class; break; - case IMGTOOLINFO_PTR_OPEN: info->open = NULL; break; + case IMGTOOLINFO_PTR_OPEN: info->open = nullptr; break; case IMGTOOLINFO_PTR_BEGIN_ENUM: info->begin_enum = vzdos_diskimage_beginenum; break; case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = vzdos_diskimage_nextenum; break; case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = vzdos_diskimage_freespace; break; diff --git a/src/tools/imgtool/stream.cpp b/src/tools/imgtool/stream.cpp index 05f105afbc2..f68f8b4eac6 100644 --- a/src/tools/imgtool/stream.cpp +++ b/src/tools/imgtool/stream.cpp @@ -21,6 +21,7 @@ #include <cstdarg> #include <cstdio> #include <cstring> +#include <tuple> @@ -70,7 +71,7 @@ public: return std::error_condition(); } - virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition read_some(void *buffer, std::size_t length, std::size_t &actual) noexcept override { actual = m_stream->read(buffer, length); if (actual < length) @@ -78,7 +79,7 @@ public: return std::error_condition(); } - virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition read_some_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override { std::uint64_t const pos = m_stream->tell(); m_stream->seek(offset, SEEK_SET); @@ -111,7 +112,7 @@ public: return std::error_condition(); } - virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition write_some(void const *buffer, std::size_t length, std::size_t &actual) noexcept override { std::uint64_t const pos = m_stream->tell(); std::uint64_t size = m_stream->size(); @@ -124,7 +125,7 @@ public: return (actual == length) ? std::error_condition() : std::errc::io_error; } - virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition write_some_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override { std::uint64_t const pos = m_stream->tell(); std::uint64_t size = m_stream->size(); @@ -391,13 +392,14 @@ util::core_file *stream::core_file() uint32_t stream::read(void *buf, uint32_t sz) { + std::error_condition err; size_t result = 0; switch(imgtype) { case IMG_FILE: if (!file->seek(position, SEEK_SET)) - file->read(buf, sz, result); // FIXME: check error return + std::tie(err, result) = util::read(*file, buf, sz); // FIXME: check error return break; case IMG_MEM: @@ -424,6 +426,7 @@ uint32_t stream::read(void *buf, uint32_t sz) uint32_t stream::write(const void *buf, uint32_t sz) { + std::error_condition err; size_t result = 0; switch(imgtype) @@ -455,7 +458,7 @@ uint32_t stream::write(const void *buf, uint32_t sz) case IMG_FILE: if (!file->seek(position, SEEK_SET)) - file->write(buf, sz, result); // FIXME: check error return + std::tie(err, result) = util::write(*file, buf, sz); // FIXME: check error return break; default: diff --git a/src/tools/ldresample.cpp b/src/tools/ldresample.cpp index 0836fd4b7a9..4fcd19c3afc 100644 --- a/src/tools/ldresample.cpp +++ b/src/tools/ldresample.cpp @@ -249,7 +249,7 @@ static bool read_chd(chd_file &file, uint32_t field, movie_info &info, uint32_t file.codec_configure(CHD_CODEC_AVHUFF, AVHUFF_CODEC_DECOMPRESS_CONFIG, &avconfig); // read the field - std::error_condition chderr = file.read_hunk(field, nullptr); + std::error_condition chderr = file.codec_process_hunk(field); return !chderr; } diff --git a/src/tools/ldverify.cpp b/src/tools/ldverify.cpp index bb95c3fbad4..bdb3b8c0a1f 100644 --- a/src/tools/ldverify.cpp +++ b/src/tools/ldverify.cpp @@ -252,7 +252,7 @@ static int read_chd(void *file, int frame, bitmap_yuy16 &bitmap, int16_t *lsound chdfile->codec_configure(CHD_CODEC_AVHUFF, AVHUFF_CODEC_DECOMPRESS_CONFIG, &avconfig); // read the frame - std::error_condition chderr = chdfile->read_hunk(frame * interlace_factor + fieldnum, nullptr); + std::error_condition chderr = chdfile->codec_process_hunk(frame * interlace_factor + fieldnum); if (chderr) return false; diff --git a/src/tools/regrep.cpp b/src/tools/regrep.cpp index fd6f002ac89..316ef805f5a 100644 --- a/src/tools/regrep.cpp +++ b/src/tools/regrep.cpp @@ -14,6 +14,7 @@ #include "osdcomm.h" +#include <algorithm> #include <cassert> #include <cctype> #include <cstdio> @@ -67,8 +68,8 @@ struct summary_file summary_file * next; char name[20]; char source[100]; - uint8_t status[MAX_COMPARES]; - uint8_t matchbitmap[MAX_COMPARES]; + uint8_t status[MAX_COMPARES]; + uint8_t matchbitmap[MAX_COMPARES]; std::string text[MAX_COMPARES]; }; @@ -224,7 +225,7 @@ static inline int get_unique_index(const summary_file *curfile, int index) int main(int argc, char *argv[]) { - uint32_t bufsize; + size_t bufsize; void *buffer; int listnum; int result; @@ -290,7 +291,7 @@ int main(int argc, char *argv[]) static summary_file *get_file(const char *filename) { - summary_file *file; + summary_file *file = nullptr; /* use the first two characters as a lookup */ for (file = filehash[filename[0] & 0x7f][filename[1] & 0x7f]; file != nullptr; file = file->next) @@ -298,10 +299,14 @@ static summary_file *get_file(const char *filename) return file; /* didn't find one -- allocate */ - file = (summary_file *)malloc(sizeof(*file)); + file = new (std::nothrow) summary_file; if (file == nullptr) return nullptr; - memset(file, 0, sizeof(*file)); + file->next = nullptr; + std::fill(std::begin(file->name), std::end(file->name), '\0'); + std::fill(std::begin(file->source), std::end(file->source), '\0'); + std::fill(std::begin(file->status), std::end(file->status), 0); + std::fill(std::begin(file->matchbitmap), std::end(file->matchbitmap), 0); /* set the name so we find it in the future */ strcpy(file->name, filename); @@ -510,7 +515,7 @@ static int CLIB_DECL compare_file(const void *file0ptr, const void *file1ptr) into a single, sorted list -------------------------------------------------*/ -static summary_file *sort_file_list(void) +static summary_file *sort_file_list() { summary_file *listhead, **tailptr, *curfile, **filearray; int numfiles, filenum; @@ -577,8 +582,7 @@ static util::core_file::ptr create_file_and_output_header(std::string_view filen /* print a header */ std::string modified(templatefile); strreplace(modified, "<!--TITLE-->", title); - std::size_t written; - file->write(modified.c_str(), modified.length(), written); // FIXME: check for errors + /*auto const [err, written] =*/ write(*file, modified.c_str(), modified.length()); // FIXME: check for errors /* return the file */ return file; @@ -594,8 +598,7 @@ static void output_footer_and_close_file(util::write_stream::ptr &&file, std::st { std::string modified(templatefile); strreplace(modified, "<!--TITLE-->", title); - std::size_t written; - file->write(modified.c_str(), modified.length(), written); // FIXME: check for errors + /*auto const [err, written] =*/ write(*file, modified.c_str(), modified.length()); // FIXME: check for errors file.reset(); } diff --git a/src/tools/romcmp.cpp b/src/tools/romcmp.cpp index 01a234b9736..e3ae03c8f5e 100644 --- a/src/tools/romcmp.cpp +++ b/src/tools/romcmp.cpp @@ -559,7 +559,10 @@ static int load_files(int i, int *found, const char *path) else { if (zip->decompress(file.buf.get(), file.size)) + { + printf("%s: Decompression failed\n", file.name.c_str()); file.free(); + } } file.listed = 0; diff --git a/src/tools/split.cpp b/src/tools/split.cpp index 10078060448..5668e6e254c 100644 --- a/src/tools/split.cpp +++ b/src/tools/split.cpp @@ -12,11 +12,13 @@ #include "corestr.h" #include "hashing.h" +#include <cassert> +#include <cctype> #include <cstdio> #include <cstdlib> #include <cstring> -#include <cctype> -#include <cassert> +#include <tuple> +#include <type_traits> #define DEFAULT_SPLIT_SIZE 100 #define MAX_PARTS 1000 @@ -34,11 +36,19 @@ hash over a buffer and return a string -------------------------------------------------*/ -static void compute_hash_as_string(std::string &buffer, void *data, uint32_t length) +static void compute_hash_as_string(std::string &buffer, const void *data, size_t length) { // compute the SHA1 util::sha1_creator sha1; - sha1.append(data, length); + do + { + // deal with size_t potentially being bigger than 32 bits + auto const chunk = std::min<std::common_type_t<size_t, uint32_t> >(length, std::numeric_limits<uint32_t>::max()); + sha1.append(data, chunk); + length -= chunk; + data = reinterpret_cast<const uint8_t *>(data) + chunk; + } + while (length); const util::sha1_t sha1digest = sha1.finish(); // expand the digest to a string @@ -141,7 +151,7 @@ static int split_file(const char *filename, const char *basename, uint32_t split // read as much as we can from the file size_t length; - infile->read(splitbuffer, splitsize, length); // FIXME check error return + std::tie(filerr, length) = read(*infile, splitbuffer, splitsize); // FIXME check error return if (length == 0) break; @@ -167,8 +177,8 @@ static int split_file(const char *filename, const char *basename, uint32_t split // write the data size_t actual; - filerr = outfile->write(splitbuffer, length, actual); - if (filerr || (actual != length) || outfile->flush()) + std::tie(filerr, actual) = write(*outfile, splitbuffer, length); + if (filerr || outfile->flush()) { printf("\n"); fprintf(stderr, "Fatal error: Error writing output file (out of space?)\n"); @@ -302,7 +312,7 @@ static int join_file(const char *filename, const char *outname, int write_output // read the file's contents infilename.insert(0, basepath); - uint32_t length; + size_t length; filerr = util::core_file::load(infilename.c_str(), &splitbuffer, length); if (filerr) { @@ -328,8 +338,8 @@ static int join_file(const char *filename, const char *outname, int write_output printf(" writing..."); size_t actual; - filerr = outfile->write(splitbuffer, length, actual); - if (filerr || (actual != length) || outfile->flush()) + std::tie(filerr, actual) = write(*outfile, splitbuffer, length); + if (filerr || outfile->flush()) { printf("\n"); fprintf(stderr, "Fatal error: Error writing output file (out of space?)\n"); diff --git a/src/tools/srcclean.cpp b/src/tools/srcclean.cpp index d5429ae4823..63809b57f1e 100644 --- a/src/tools/srcclean.cpp +++ b/src/tools/srcclean.cpp @@ -2305,11 +2305,22 @@ int main(int argc, char *argv[]) ++failures; continue; } - std::size_t block; - while (remaining && !infile->read(original, (std::min)(std::uint64_t(sizeof(original)), remaining), block) && block) + while (remaining) { - remaining -= block; - cleaner->process(original, original + block); + std::size_t block((std::min)(std::uint64_t(sizeof(original)), remaining)); + std::size_t actual; + std::error_condition const readerr(infile->read_some(original, block, actual)); + if (readerr) + { + if (std::errc::interrupted != readerr) + break; + } + else if (!actual) + { + break; + } + remaining -= actual; + cleaner->process(original, original + actual); } if (remaining) { diff --git a/src/tools/unidasm.cpp b/src/tools/unidasm.cpp index 50c5e5ba7e8..be64dc9cb72 100644 --- a/src/tools/unidasm.cpp +++ b/src/tools/unidasm.cpp @@ -27,8 +27,10 @@ using util::BIT; #include "cpu/asap/asapdasm.h" #include "cpu/avr8/avr8dasm.h" #include "cpu/bcp/bcpdasm.h" +#include "cpu/c33/c33dasm.h" #include "cpu/capricorn/capricorn_dasm.h" #include "cpu/ccpu/ccpudasm.h" +#include "cpu/cdc160/cdc160d.h" #include "cpu/cdc1700/cdc1700d.h" #include "cpu/clipper/clipperd.h" #include "cpu/cop400/cop410ds.h" @@ -67,6 +69,7 @@ using util::BIT; #include "cpu/hcd62121/hcd62121d.h" #include "cpu/hd61700/hd61700d.h" #include "cpu/hmcs40/hmcs40d.h" +#include "cpu/hmcs400/hmcs400d.h" #include "cpu/hp2100/hp2100d.h" #include "cpu/hpc/hpcdasm.h" #include "cpu/hphybrid/hphybrid_dasm.h" @@ -94,11 +97,11 @@ using util::BIT; #include "cpu/m6502/m6502d.h" #include "cpu/m6502/m6509d.h" #include "cpu/m6502/m6510d.h" -#include "cpu/m6502/m65c02d.h" #include "cpu/m6502/m65ce02d.h" #include "cpu/m6502/m740d.h" #include "cpu/m6502/r65c02d.h" #include "cpu/m6502/r65c19d.h" +#include "cpu/m6502/w65c02d.h" #include "cpu/m6502/xavixd.h" #include "cpu/m6502/xavix2000d.h" #include "cpu/m6800/6800dasm.h" @@ -121,19 +124,24 @@ using util::BIT; #include "cpu/minx/minxd.h" #include "cpu/mips/mips3dsm.h" #include "cpu/mips/mips1dsm.h" +#include "cpu/mipsx/mipsxdasm.h" #include "cpu/mk1/mk1dasm.h" #include "cpu/mn1400/mn1400d.h" #include "cpu/mn1610/mn1610d.h" #include "cpu/mn1880/mn1880d.h" #include "cpu/mn10200/mn102dis.h" +#include "cpu/mn10300/mn103dasm.h" +#include "cpu/mpk1839/kl1839vm1dasm.h" #include "cpu/msm65x2/msm65x2d.h" #include "cpu/nanoprocessor/nanoprocessor_dasm.h" #include "cpu/nec/necdasm.h" #include "cpu/nios2/nios2dasm.h" #include "cpu/nova/novadasm.h" -#include "cpu/ns32000/ns32000dasm.h" +#include "cpu/ns32000/ns32000d.h" #include "cpu/nuon/nuondasm.h" +#include "cpu/olms66k/nx8dasm.h" #include "cpu/pace/pacedasm.h" +#include "cpu/palm/palmd.h" #include "cpu/patinhofeio/patinho_feio_dasm.h" #include "cpu/pdp1/pdp1dasm.h" #include "cpu/pdp8/pdp8dasm.h" @@ -191,6 +199,7 @@ using util::BIT; #include "cpu/unsp/unspdasm.h" #include "cpu/upd177x/upd177xd.h" #include "cpu/upd7725/dasm7725.h" +#include "cpu/upd777/upd777dasm.h" #include "cpu/upd7810/upd7810_dasm.h" #include "cpu/upd78k/upd78k0d.h" #include "cpu/upd78k/upd78k1d.h" @@ -205,10 +214,12 @@ using util::BIT; #include "cpu/vt50/vt50dasm.h" #include "cpu/vt61/vt61dasm.h" #include "cpu/we32000/we32100d.h" +#include "cpu/xa/xadasm.h" #include "cpu/xavix2/xavix2d.h" #include "cpu/xtensa/xtensad.h" #include "cpu/z180/z180dasm.h" #include "cpu/z8/z8dasm.h" +#include "cpu/z80/r800dasm.h" #include "cpu/z80/z80dasm.h" #include "cpu/z8000/8000dasm.h" @@ -262,7 +273,6 @@ struct g65816_unidasm_t : g65816_disassembler::config bool x_flag; g65816_unidasm_t() { m_flag = false; x_flag = false; } - virtual ~g65816_unidasm_t() override = default; virtual bool get_m_flag() const override { return m_flag; } virtual bool get_x_flag() const override { return x_flag; } } g65816_unidasm; @@ -338,11 +348,9 @@ struct z8000_unidasm_t : z8000_disassembler::config struct hyperstone_unidasm_t : hyperstone_disassembler::config { bool h; - u8 fp; - hyperstone_unidasm_t() { h = false; fp = 0; } + hyperstone_unidasm_t() { h = false; } virtual ~hyperstone_unidasm_t() = default; - virtual u8 get_fp() const { return fp; } virtual bool get_h() const { return h; } } hyperstone_unidasm; @@ -412,8 +420,11 @@ static const dasm_table_entry dasm_table[] = { "b5500", le, 0, []() -> util::disasm_interface * { return new b5500_disassembler; } }, { "b6000", le, 0, []() -> util::disasm_interface * { return new b6000_disassembler; } }, { "b6100", le, 0, []() -> util::disasm_interface * { return new b6100_disassembler; } }, + { "c33", le, 0, []() -> util::disasm_interface * { return new c33_disassembler; } }, { "capricorn", le, 0, []() -> util::disasm_interface * { return new capricorn_disassembler; } }, { "ccpu", le, 0, []() -> util::disasm_interface * { return new ccpu_disassembler; } }, + { "cdc160", be, -1, []() -> util::disasm_interface * { return new cdc160_disassembler; } }, + { "cdc160a", be, -1, []() -> util::disasm_interface * { return new cdc160a_disassembler; } }, { "cdc1700", be, -1, []() -> util::disasm_interface * { return new cdc1700_disassembler; } }, { "cdp1801", le, 0, []() -> util::disasm_interface * { return new cosmac_disassembler(cosmac_disassembler::TYPE_1801); } }, { "cdp1802", le, 0, []() -> util::disasm_interface * { return new cosmac_disassembler(cosmac_disassembler::TYPE_1802); } }, @@ -468,6 +479,7 @@ static const dasm_table_entry dasm_table[] = { "hd6309", be, 0, []() -> util::disasm_interface * { return new hd6309_disassembler; } }, { "hd63701", be, 0, []() -> util::disasm_interface * { return new m680x_disassembler(63701); } }, { "hmcs40", le, -1, []() -> util::disasm_interface * { return new hmcs40_disassembler; } }, + { "hmcs400", le, -1, []() -> util::disasm_interface * { return new hmcs400_disassembler; } }, { "hp2100", be, -1, []() -> util::disasm_interface * { return new hp2100_disassembler; } }, { "hp21mx", be, -1, []() -> util::disasm_interface * { return new hp21mx_disassembler; } }, { "hp_5061_3001", be, -1, []() -> util::disasm_interface * { return new hp_5061_3001_disassembler; } }, @@ -500,6 +512,7 @@ static const dasm_table_entry dasm_table[] = { "jaguargpu", be, 0, []() -> util::disasm_interface * { return new jaguar_disassembler(jaguar_disassembler::variant::GPU); } }, { "konami", be, 0, []() -> util::disasm_interface * { return new konami_disassembler; } }, { "ks0164", be, 0, []() -> util::disasm_interface * { return new ks0164_disassembler; } }, + { "kl1839vm1", be, 0, []() -> util::disasm_interface * { return new kl1839vm1_disassembler; } }, { "lc57", be, 0, []() -> util::disasm_interface * { return new lc57_disassembler; } }, { "lc58", be, -1, []() -> util::disasm_interface * { return new lc58_disassembler; } }, { "lc8670", be, 0, []() -> util::disasm_interface * { return new lc8670_disassembler; } }, @@ -514,7 +527,6 @@ static const dasm_table_entry dasm_table[] = { "m6502", le, 0, []() -> util::disasm_interface * { return new m6502_disassembler; } }, { "m6509", le, 0, []() -> util::disasm_interface * { return new m6509_disassembler; } }, { "m6510", le, 0, []() -> util::disasm_interface * { return new m6510_disassembler; } }, - { "m65c02", le, 0, []() -> util::disasm_interface * { return new m65c02_disassembler; } }, { "m65ce02", le, 0, []() -> util::disasm_interface * { return new m65ce02_disassembler; } }, { "m6800", be, 0, []() -> util::disasm_interface * { return new m680x_disassembler(6800); } }, { "m68000", be, 0, []() -> util::disasm_interface * { return new m68k_disassembler(m68k_disassembler::TYPE_68000); } }, @@ -533,7 +545,7 @@ static const dasm_table_entry dasm_table[] = { "m740", le, 0, []() -> util::disasm_interface * { return new m740_disassembler(&m740_unidasm); } }, { "mb86233", le, -2, []() -> util::disasm_interface * { return new mb86233_disassembler; } }, { "mb86235", le, -3, []() -> util::disasm_interface * { return new mb86235_disassembler; } }, - { "mb88", le, 0, []() -> util::disasm_interface * { return new mb88_disassembler; } }, + { "mb88xx", le, 0, []() -> util::disasm_interface * { return new mb88_disassembler; } }, { "mc88100", be, 0, []() -> util::disasm_interface * { return new mc88100_disassembler; } }, { "mc88110", be, 0, []() -> util::disasm_interface * { return new mc88110_disassembler; } }, { "mcs48", le, 0, []() -> util::disasm_interface * { return new mcs48_disassembler(false, false); } }, @@ -542,11 +554,13 @@ static const dasm_table_entry dasm_table[] = { "mips1le", le, 0, []() -> util::disasm_interface * { return new mips1_disassembler; } }, { "mips3be", be, 0, []() -> util::disasm_interface * { return new mips3_disassembler; } }, { "mips3le", le, 0, []() -> util::disasm_interface * { return new mips3_disassembler; } }, + { "mipsx", be, 0, []() -> util::disasm_interface * { return new mipsx_disassembler; } }, { "mk1", le, 0, []() -> util::disasm_interface * { return new mk1_disassembler; } }, { "mm5799", le, 0, []() -> util::disasm_interface * { return new mm5799_disassembler; } }, { "mm76", le, 0, []() -> util::disasm_interface * { return new mm76_disassembler; } }, { "mm78", le, 0, []() -> util::disasm_interface * { return new mm78_disassembler; } }, { "mn10200", le, 0, []() -> util::disasm_interface * { return new mn10200_disassembler; } }, + { "mn10300", le, 0, []() -> util::disasm_interface * { return new mn10300_disassembler; } }, { "mn1400", le, 0, []() -> util::disasm_interface * { return new mn1400_disassembler; } }, { "mn1610", be, -1, []() -> util::disasm_interface * { return new mn1610_disassembler; } }, { "mn1613", be, -1, []() -> util::disasm_interface * { return new mn1613_disassembler; } }, @@ -561,7 +575,11 @@ static const dasm_table_entry dasm_table[] = { "ns32000", le, 0, []() -> util::disasm_interface * { return new ns32000_disassembler; } }, { "nuon", be, 0, []() -> util::disasm_interface * { return new nuon_disassembler; } }, { "nsc8105", be, 0, []() -> util::disasm_interface * { return new m680x_disassembler(8105); } }, + { "nx8_500s", le, 0, []() -> util::disasm_interface * { return new nx8_500s_disassembler; } }, + { "p8xc552", le, 0, []() -> util::disasm_interface * { return new p8xc552_disassembler; } }, + { "p8xc562", le, 0, []() -> util::disasm_interface * { return new p8xc562_disassembler; } }, { "pace", le, -1, []() -> util::disasm_interface * { return new pace_disassembler; } }, + { "palm", be, 0, []() -> util::disasm_interface * { return new palm_disassembler; } }, { "patinho_feio", le, 0, []() -> util::disasm_interface * { return new patinho_feio_disassembler; } }, { "pdp1", be, -2, []() -> util::disasm_interface * { return new pdp1_disassembler; } }, { "pdp8", be, -1, []() -> util::disasm_interface * { return new pdp8_disassembler; } }, @@ -581,6 +599,7 @@ static const dasm_table_entry dasm_table[] = { "psxcpu", le, 0, []() -> util::disasm_interface * { return new psxcpu_disassembler; } }, { "r65c02", le, 0, []() -> util::disasm_interface * { return new r65c02_disassembler; } }, { "r65c19", le, 0, []() -> util::disasm_interface * { return new r65c19_disassembler; } }, + { "r800", le, 0, []() -> util::disasm_interface * { return new r800_disassembler; } }, { "romp", be, 0, []() -> util::disasm_interface * { return new romp_disassembler; } }, { "rsp", le, 0, []() -> util::disasm_interface * { return new rsp_disassembler; } }, { "rupi44", le, 0, []() -> util::disasm_interface * { return new rupi44_disassembler; } }, @@ -657,6 +676,7 @@ static const dasm_table_entry dasm_table[] = { "unsp12", be, -1, []() -> util::disasm_interface * { return new unsp_12_disassembler; } }, { "unsp20", be, -1, []() -> util::disasm_interface * { return new unsp_20_disassembler; } }, { "upd177x", be, -1, []() -> util::disasm_interface * { return new upd177x_disassembler; } }, + { "upd777", be, -1, []() -> util::disasm_interface * { return new upd777_disassembler; } }, { "upd7725", be, -2, []() -> util::disasm_interface * { return new necdsp_disassembler; } }, { "upd7801", le, 0, []() -> util::disasm_interface * { return new upd7801_disassembler; } }, { "upd78c05", le, 0, []() -> util::disasm_interface * { return new upd78c05_disassembler; } }, @@ -709,10 +729,12 @@ static const dasm_table_entry dasm_table[] = { "vt50", le, 0, []() -> util::disasm_interface * { return new vt50_disassembler; } }, { "vt52", le, 0, []() -> util::disasm_interface * { return new vt52_disassembler; } }, { "vt61", le, -1, []() -> util::disasm_interface * { return new vt61_disassembler; } }, + { "w65c02", le, 0, []() -> util::disasm_interface * { return new w65c02_disassembler; } }, { "we32100", be, 0, []() -> util::disasm_interface * { return new we32100_disassembler; } }, { "x86_16", le, 0, []() -> util::disasm_interface * { i386_unidasm.mode = 16; return new i386_disassembler(&i386_unidasm); } }, { "x86_32", le, 0, []() -> util::disasm_interface * { i386_unidasm.mode = 32; return new i386_disassembler(&i386_unidasm); } }, { "x86_64", le, 0, []() -> util::disasm_interface * { i386_unidasm.mode = 64; return new i386_disassembler(&i386_unidasm); } }, + { "xa", le, 0, []() -> util::disasm_interface * { return new xa_dasm; } }, { "xavix", le, 0, []() -> util::disasm_interface * { return new xavix_disassembler; } }, { "xavix2000", le, 0, []() -> util::disasm_interface * { return new xavix2000_disassembler; } }, { "xavix2", le, 0, []() -> util::disasm_interface * { return new xavix2_disassembler; } }, @@ -1297,8 +1319,7 @@ int disasm_file(util::random_read &file, u64 length, options &opts) base_buffer.data.resize(rounded_size + 8, 0x00); base_buffer.size = length; base_buffer.base_pc = opts.basepc; - std::size_t actual; - std::error_condition filerr = file.read_at(opts.skip, &base_buffer.data[0], length - opts.skip, actual); + auto const [filerr, actual] = read_at(file, opts.skip, &base_buffer.data[0], length - opts.skip); if(filerr) { std::fprintf(stderr, "Error reading from file '%s' (%s)\n", opts.filename, filerr.message().c_str()); return 1; |