diff options
Diffstat (limited to 'src/tools')
68 files changed, 8905 insertions, 14892 deletions
diff --git a/src/tools/aueffectutil.mm b/src/tools/aueffectutil.mm index ccc090d0fa8..b8a83de4c64 100644 --- a/src/tools/aueffectutil.mm +++ b/src/tools/aueffectutil.mm @@ -13,32 +13,15 @@ #include <utility> #include <vector> -#include <stdlib.h> - - -#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 +#include <cstdlib> 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; } } @@ -772,7 +752,7 @@ static void UpdateChangeCountCallback( NSMenu *submenu; NSString *const appName = [(NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle()) objectForKey:@"CFBundleName"]; - NSMenu *const menu = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"Application"]; + NSMenu *const menu = [[NSMenu alloc] initWithTitle:@"Application"]; item = [parent addItemWithTitle:@"Application" action:NULL keyEquivalent:@""]; [parent setSubmenu:menu forItem:item]; [menu release]; @@ -784,7 +764,7 @@ static void UpdateChangeCountCallback( [menu addItem:[NSMenuItem separatorItem]]; item = [menu addItemWithTitle:@"Services" action:NULL keyEquivalent:@""]; - submenu = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"Services"]; + submenu = [[NSMenu alloc] initWithTitle:@"Services"]; [menu setSubmenu:submenu forItem:item]; [submenu release]; [NSApp setServicesMenu:submenu]; @@ -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/castool.cpp b/src/tools/castool.cpp index 6c10cfe4ed8..b5fa9cf7d39 100644 --- a/src/tools/castool.cpp +++ b/src/tools/castool.cpp @@ -10,15 +10,6 @@ ***************************************************************************/ -#include <stdio.h> -#include <string.h> -#include <ctype.h> -#include <stdlib.h> -#include <time.h> -#include <assert.h> - -#include "corestr.h" - #include "formats/a26_cas.h" #include "formats/ace_tap.h" #include "formats/adam_cas.h" @@ -38,6 +29,7 @@ #include "formats/mz_cas.h" #include "formats/orao_cas.h" #include "formats/oric_tap.h" +#include "formats/p2000t_cas.h" #include "formats/p6001_cas.h" #include "formats/phc25_cas.h" #include "formats/pmd_cas.h" @@ -60,10 +52,22 @@ #include "formats/x1_tap.h" #include "formats/zx81_p.h" +#include "corestr.h" +#include "ioprocs.h" +#include "osdcomm.h" + +#include <cassert> +#include <cctype> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <ctime> + + struct SupportedCassetteFormats { const char *name; - const struct CassetteFormat * const *formats; + const cassette_image::Format * const *formats; const char *desc; }; @@ -90,6 +94,7 @@ const struct SupportedCassetteFormats formats[] = { {"mz", mz700_cassette_formats ,"Sharp MZ-700"}, {"orao", orao_cassette_formats ,"PEL Varazdin Orao"}, {"oric", oric_cassette_formats ,"Tangerine Oric"}, + {"p2000t", p2000t_cassette_formats ,"Philips P2000T"}, {"pc6001", pc6001_cassette_formats ,"NEC PC-6001"}, {"phc25", phc25_cassette_formats ,"Sanyo PHC-25"}, {"pmd85", pmd85_cassette_formats ,"Tesla PMD-85"}, @@ -157,9 +162,8 @@ int CLIB_DECL main(int argc, char *argv[]) { int i; int found =0; - const struct CassetteFormat * const *selected_formats = nullptr; - cassette_image *cassette; - FILE *f; + const cassette_image::Format * const *selected_formats = nullptr; + cassette_image::ptr cassette; if (argc > 1) { @@ -185,21 +189,26 @@ int CLIB_DECL main(int argc, char *argv[]) return -1; } - f = fopen(argv[3], "rb"); + FILE *f = fopen(argv[3], "rb"); if (!f) { fprintf(stderr, "File %s not found.\n",argv[3]); return -1; } - if (cassette_open_choices(f, &stdio_ioprocs, get_extension(argv[3]), selected_formats, CASSETTE_FLAG_READONLY, &cassette) != cassette_image::error::SUCCESS) { + auto io = util::stdio_read_write(f, 0x00); + f = nullptr; + if (!io) { + fprintf(stderr, "Out of memory.\n"); + return -1; + } + + if (cassette_image::open_choices(std::move(io), get_extension(argv[3]), selected_formats, cassette_image::FLAG_READONLY, cassette) != cassette_image::error::SUCCESS) { fprintf(stderr, "Invalid format of input file.\n"); - fclose(f); return -1; } - cassette_dump(cassette,argv[4]); - cassette_close(cassette); - fclose(f); + cassette->dump(argv[4]); + cassette.reset(); goto theend; } } diff --git a/src/tools/chdman.cpp b/src/tools/chdman.cpp index 153a4e34157..353ac88ce6b 100644 --- a/src/tools/chdman.cpp +++ b/src/tools/chdman.cpp @@ -5,39 +5,51 @@ CHD compression frontend ****************************************************************************/ -#include <stdio.h> // must be here otherwise issues with I64FMT in MINGW -#include <assert.h> +#include <stdio.h> // must be stdio.h and here otherwise issues with I64FMT in MINGW -#include "osdcore.h" -#include "corefile.h" -#include "chdcd.h" -#include "aviio.h" +// lib/util #include "avhuff.h" +#include "aviio.h" #include "bitmap.h" +#include "cdrom.h" +#include "corefile.h" +#include "coretmpl.h" +#include "hashing.h" #include "md5.h" -#include "sha1.h" +#include "multibyte.h" +#include "osdcore.h" +#include "path.h" +#include "strformat.h" #include "vbiparse.h" -#include <stdarg.h> -#include <stdlib.h> -#include <stdio.h> -#include <time.h> -#include <ctype.h> -#include <iostream> +#include <array> #include <cassert> +#include <cctype> +#include <cstdio> +#include <cstdlib> #include <cstring> +#include <ctime> +#include <iostream> #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; //************************************************************************** // CONSTANTS & DEFINES //************************************************************************** -/* MINGW has adopted the MSVC formatting for 64-bit ints as of gcc 4.4 */ -#if defined(WIN32) +// MINGW has adopted the MSVC formatting for 64-bit ints as of GCC 4.4 and deprecated it as of GCC 9.3 +#if defined(_WIN32) && defined(__GNUC__) && ((__GNUC__ < 9) || ((__GNUC__ == 9) && (__GNUC_MINOR__ < 3))) #define I64FMT "I64" #elif !defined(__APPLE__) && defined(__LP64__) #define I64FMT "l" @@ -45,16 +57,23 @@ #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 "~" @@ -66,10 +85,12 @@ const int MODE_GDI = 2; #define COMMAND_CREATE_RAW "createraw" #define COMMAND_CREATE_HD "createhd" #define COMMAND_CREATE_CD "createcd" +#define COMMAND_CREATE_DVD "createdvd" #define COMMAND_CREATE_LD "createld" #define COMMAND_EXTRACT_RAW "extractraw" #define COMMAND_EXTRACT_HD "extracthd" #define COMMAND_EXTRACT_CD "extractcd" +#define COMMAND_EXTRACT_DVD "extractdvd" #define COMMAND_EXTRACT_LD "extractld" #define COMMAND_COPY "copy" #define COMMAND_ADD_METADATA "addmeta" @@ -81,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" @@ -112,23 +134,26 @@ const int MODE_GDI = 2; // FUNCTION PROTOTYPES //************************************************************************** -typedef std::unordered_map<std::string,std::string *> parameters_t; +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> static void report_error(int error, Format &&fmt, Params &&...args); -static void do_info(parameters_t ¶ms); -static void do_verify(parameters_t ¶ms); -static void do_create_raw(parameters_t ¶ms); -static void do_create_hd(parameters_t ¶ms); -static void do_create_cd(parameters_t ¶ms); -static void do_create_ld(parameters_t ¶ms); -static void do_copy(parameters_t ¶ms); -static void do_extract_raw(parameters_t ¶ms); -static void do_extract_cd(parameters_t ¶ms); -static void do_extract_ld(parameters_t ¶ms); -static void do_add_metadata(parameters_t ¶ms); -static void do_del_metadata(parameters_t ¶ms); -static void do_dump_metadata(parameters_t ¶ms); -static void do_list_templates(parameters_t ¶ms); +static void do_info(parameters_map ¶ms); +static void do_verify(parameters_map ¶ms); +static void do_create_raw(parameters_map ¶ms); +static void do_create_hd(parameters_map ¶ms); +static void do_create_cd(parameters_map ¶ms); +static void do_create_dvd(parameters_map ¶ms); +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_ld(parameters_map ¶ms); +static void do_add_metadata(parameters_map ¶ms); +static void do_del_metadata(parameters_map ¶ms); +static void do_dump_metadata(parameters_map ¶ms); +static void do_list_templates(parameters_map ¶ms); @@ -136,6 +161,46 @@ static void do_list_templates(parameters_t ¶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 @@ -152,7 +217,7 @@ struct option_description struct command_description { const char *name; - void (*handler)(parameters_t &); + void (*handler)(parameters_map &); const char *description; const char *valid_options[16]; }; @@ -198,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; } @@ -245,11 +309,16 @@ class chd_rawfile_compressor : public chd_file_compressor { public: // construction/destruction - chd_rawfile_compressor(util::core_file &file, std::uint64_t offset = 0, std::uint64_t maxoffset = std::numeric_limits<std::uint64_t>::max()) + chd_rawfile_compressor(util::random_read &file, std::uint64_t offset = 0, std::uint64_t maxoffset = std::numeric_limits<std::uint64_t>::max()) : m_file(file) , m_offset(offset) - , m_maxoffset((std::min)(maxoffset, file.size())) { + // TODO: what to do about error getting file size? + std::uint64_t filelen; + if (!file.length(filelen)) + m_maxoffset = (std::min)(maxoffset, filelen); + else + m_maxoffset = maxoffset; } // read interface @@ -260,13 +329,15 @@ public: return 0; if (offset + length > m_maxoffset) length = m_maxoffset - offset; - m_file.seek(offset, SEEK_SET); - return m_file.read(dest, length); + if (m_file.seek(offset, SEEK_SET)) // FIXME: better error reporting? + return 0; + auto const [err, actual] = read(m_file, dest, length); // FIXME: check for error return + return actual; } private: // internal state - util::core_file & m_file; + util::random_read & m_file; std::uint64_t m_offset; std::uint64_t m_maxoffset; }; @@ -279,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) @@ -292,18 +365,18 @@ public: return 0; if (offset + length > m_maxoffset) length = m_maxoffset - offset; - chd_error err = m_file.read_bytes(offset, dest, length); - if (err != CHDERR_NONE) + std::error_condition err = m_file.read_bytes(offset, dest, length); + if (err) throw err; // if we have TOC - detect audio sectors and swap data if (m_toc) { - assert(offset % CD_FRAME_SIZE == 0); - assert(length % CD_FRAME_SIZE == 0); + assert(offset % cdrom_file::FRAME_SIZE == 0); + assert(length % cdrom_file::FRAME_SIZE == 0); - int startlba = offset / CD_FRAME_SIZE; - int lenlba = length / CD_FRAME_SIZE; + int startlba = offset / cdrom_file::FRAME_SIZE; + int lenlba = length / cdrom_file::FRAME_SIZE; uint8_t *_dest = reinterpret_cast<uint8_t *>(dest); for (int chdlba = 0; chdlba < lenlba; chdlba++) @@ -317,11 +390,11 @@ public: break; } // is it audio ? - if (m_toc->tracks[tracknum].trktype != CD_TRACK_AUDIO) + if (m_toc->tracks[tracknum].trktype != cdrom_file::CD_TRACK_AUDIO) continue; // byteswap if yes - int dataoffset = chdlba * CD_FRAME_SIZE; - for (uint32_t swapindex = dataoffset; swapindex < (dataoffset + CD_MAX_SECTOR_DATA); swapindex += 2) + int dataoffset = chdlba * cdrom_file::FRAME_SIZE; + for (uint32_t swapindex = dataoffset; swapindex < (dataoffset + cdrom_file::MAX_SECTOR_DATA); swapindex += 2) { uint8_t temp = _dest[swapindex]; _dest[swapindex] = _dest[swapindex + 1]; @@ -333,7 +406,7 @@ public: return length; } -const cdrom_toc * m_toc; +const cdrom_file::toc * m_toc; private: // internal state @@ -349,10 +422,12 @@ class chd_cd_compressor : public chd_file_compressor { public: // construction/destruction - chd_cd_compressor(cdrom_toc &toc, chdcd_track_input_info &info) - : m_file(), - m_toc(toc), - m_info(info) { } + chd_cd_compressor(cdrom_file::toc &toc, cdrom_file::track_input_info &info) + : m_file() + , m_toc(toc) + , m_info(info) + { + } ~chd_cd_compressor() { @@ -362,8 +437,8 @@ public: virtual uint32_t read_data(void *_dest, uint64_t offset, uint32_t length) { // verify assumptions made below - assert(offset % CD_FRAME_SIZE == 0); - assert(length % CD_FRAME_SIZE == 0); + assert(offset % cdrom_file::FRAME_SIZE == 0); + assert(length % cdrom_file::FRAME_SIZE == 0); // initialize destination to 0 so that unused areas are filled uint8_t *dest = reinterpret_cast<uint8_t *>(_dest); @@ -374,8 +449,9 @@ public: uint32_t length_remaining = length; for (int tracknum = 0; tracknum < m_toc.numtrks; tracknum++) { - const cdrom_track_info &trackinfo = m_toc.tracks[tracknum]; - uint64_t endoffs = startoffs + (uint64_t)(trackinfo.frames + trackinfo.extraframes) * CD_FRAME_SIZE; + 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 @@ -383,33 +459,56 @@ public: { m_file.reset(); m_lastfile = m_info.track[tracknum].fname; - osd_file::error filerr = util::core_file::open(m_lastfile, OPEN_FLAG_READ, m_file); - if (filerr != osd_file::error::NONE) - report_error(1, "Error opening input file (%s)'", m_lastfile.c_str()); + std::error_condition const filerr = util::core_file::open(m_lastfile, OPEN_FLAG_READ, m_file); + if (filerr) + report_error(1, "Error opening input file (%s): %s", m_lastfile, filerr.message()); } // iterate over frames 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 = 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)trackinfo.splitframes == 0L) + split_track_start = UINT64_MAX; + while (length_remaining != 0 && offset < endoffs) { // determine start of current frame - uint64_t src_frame_start = src_track_start + ((offset - startoffs) / CD_FRAME_SIZE) * bytesperframe; + 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 && 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; + std::error_condition const filerr = util::core_file::open(m_lastfile, OPEN_FLAG_READ, m_file); + if (filerr) + report_error(1, "Error opening input file (%s): %s", m_lastfile, filerr.message()); + } + 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); } else { - m_file->seek(src_frame_start, SEEK_SET); - uint32_t count = m_file->read(dest, bytesperframe); - if (count != bytesperframe) - report_error(1, "Error reading input file (%s)'", m_lastfile.c_str()); + std::error_condition err = m_file->seek( + (src_frame_start >= split_track_start) + ? src_frame_start - split_track_start + : src_frame_start, + SEEK_SET); + std::size_t count = 0; + if (!err) + std::tie(err, count) = read(*m_file, dest, bytesperframe); + if (err || (count != bytesperframe)) + report_error(1, "Error reading input file (%s)'", m_lastfile); } // swap if appropriate @@ -423,9 +522,9 @@ public: } // advance - offset += CD_FRAME_SIZE; - dest += CD_FRAME_SIZE; - length_remaining -= CD_FRAME_SIZE; + offset += cdrom_file::FRAME_SIZE; + dest += cdrom_file::FRAME_SIZE; + length_remaining -= cdrom_file::FRAME_SIZE; if (length_remaining == 0) break; } @@ -439,10 +538,10 @@ public: private: // internal state - std::string m_lastfile; - util::core_file::ptr m_file; - cdrom_toc & m_toc; - chdcd_track_input_info & m_info; + std::string m_lastfile; + util::core_file::ptr m_file; + cdrom_file::toc & m_toc; + cdrom_file::track_input_info &m_info; }; @@ -453,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; } @@ -475,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 @@ -483,7 +585,7 @@ public: uint32_t samples = (uint64_t(m_info.rate) * uint64_t(effframe + 1) * uint64_t(1000000) + m_info.fps_times_1million - 1) / uint64_t(m_info.fps_times_1million) - first_sample; // loop over channels and read the samples - int channels = unsigned((std::min<std::size_t>)(m_info.channels, ARRAY_LENGTH(m_audio))); + int channels = unsigned(std::min<std::size_t>(m_info.channels, std::size(m_audio))); EQUIVALENT_ARRAY(m_audio, int16_t *) samplesptr; for (int chnum = 0; chnum < channels; chnum++) { @@ -505,7 +607,7 @@ public: if (m_info.height == 524/2 || m_info.height == 624/2) { vbi_metadata vbi; - vbi_parse_all(&subbitmap.pix16(0), subbitmap.rowpixels(), subbitmap.width(), 8, &vbi); + vbi_parse_all(&subbitmap.pix(0), subbitmap.rowpixels(), subbitmap.width(), 8, &vbi); vbi_metadata_pack(&m_ldframedata[framenum * VBI_PACKED_BYTES], framenum, &vbi); } @@ -531,6 +633,7 @@ public: dest += bytes_to_copy; length_remaining -= bytes_to_copy; } + } return length; } @@ -540,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; }; @@ -558,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 @@ -571,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" }, @@ -583,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" }, @@ -611,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 } }, @@ -625,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 } @@ -664,6 +770,21 @@ static const command_description s_commands[] = OPTION_NUMPROCESSORS } }, + { COMMAND_CREATE_DVD, do_create_dvd, ": create a DVD CHD from the input file", + { + REQUIRED OPTION_OUTPUT, + 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 + } + }, { COMMAND_CREATE_LD, do_create_ld, ": create a laserdisc CHD from the input file", { @@ -709,12 +830,26 @@ 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_raw, ": extract DVD file from a CHD input file", + { + REQUIRED OPTION_OUTPUT, + 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 + } + }, + { COMMAND_EXTRACT_LD, do_extract_ld, ": extract laserdisc AVI from a CHD input file", { REQUIRED OPTION_OUTPUT, @@ -782,11 +917,19 @@ static const command_description s_commands[] = // hard disk templates static const hd_template s_hd_templates[] = { - { "Conner", "CFA170A", 332, 16, 63, 512 }, // 163 MB - { "Rodime", "R0201", 321, 2, 16, 512 }, // 5 MB - { "Rodime", "R0202", 321, 4, 16, 512 }, // 10 MB - { "Rodime", "R0203", 321, 6, 16, 512 }, // 15 MB - { "Rodime", "R0204", 321, 8, 16, 512 }, // 20 MB + { "Conner", "CFA170A", 332, 16, 63, 512 }, // 163 MB + { "Rodime", "R0201", 321, 2, 16, 512 }, // 5 MB + { "Rodime", "R0202", 321, 4, 16, 512 }, // 10 MB + { "Rodime", "R0203", 321, 6, 16, 512 }, // 15 MB + { "Rodime", "R0204", 321, 8, 16, 512 }, // 20 MB + { "Seagate", "ST-213", 615, 2, 17, 512 }, // 10 MB + { "Seagate", "ST-225", 615, 4, 17, 512 }, // 20 MB + { "Seagate", "ST-251", 820, 6, 17, 512 }, // 40 MB + { "Seagate", "ST-3600N", 1877, 7, 76, 512 }, // 525 MB + { "Maxtor", "LXT-213S", 1314, 7, 53, 512 }, // 200 MB + { "Maxtor", "LXT-340S", 1574, 7, 70, 512 }, // 340 MB + { "Maxtor", "MXT-540SL", 2466, 7, 87, 512 }, // 540 MB + { "Micropolis", "1528", 2094, 15, 83, 512 }, // 1342 MB }; @@ -799,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)...); @@ -815,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(); @@ -833,20 +978,20 @@ template <typename Format, typename... Params> static void progress(bool forceit // print_help - print help for all the commands //------------------------------------------------- -static int print_help(const char *argv0, const char *error = nullptr) +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, 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, 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; } @@ -856,16 +1001,16 @@ static int print_help(const char *argv0, const char *error = nullptr) // command //------------------------------------------------- -static int print_help(const char *argv0, const command_description &desc, const char *error = nullptr) +static int print_help(const std::string &argv0, const command_description &desc, const char *error = nullptr) { // 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, desc.name); - for (int valid = 0; valid < ARRAY_LENGTH(desc.valid_options); valid++) + 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 const char *option = desc.valid_options[valid]; @@ -880,10 +1025,10 @@ static int print_help(const char *argv0, const command_description &desc, const 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; @@ -967,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 @@ -979,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; @@ -991,7 +1146,10 @@ static void guess_chs(std::string *filename, uint64_t filesize, int sectorsize, sectors = cursectors; return; } + } } + } + } } @@ -1000,24 +1158,24 @@ static void guess_chs(std::string *filename, uint64_t filesize, int sectorsize, // standard set of input CHD parameters //------------------------------------------------- -static void parse_input_chd_parameters(const parameters_t ¶ms, chd_file &input_chd, chd_file &input_parent_chd, bool writeable = false) +static void parse_input_chd_parameters(const parameters_map ¶ms, chd_file &input_chd, chd_file &input_parent_chd, bool writeable = false) { // process input parent file auto input_chd_parent_str = params.find(OPTION_INPUT_PARENT); if (input_chd_parent_str != params.end()) { - chd_error err = input_parent_chd.open(input_chd_parent_str->second->c_str()); - if (err != CHDERR_NONE) - report_error(1, "Error opening parent CHD file (%s): %s", input_chd_parent_str->second->c_str(), chd_file::error_string(err)); + std::error_condition err = input_parent_chd.open(*input_chd_parent_str->second); + if (err) + report_error(1, "Error opening parent CHD file (%s): %s", *input_chd_parent_str->second, err.message()); } // process input file auto input_chd_str = params.find(OPTION_INPUT); if (input_chd_str != params.end()) { - chd_error err = input_chd.open(input_chd_str->second->c_str(), writeable, input_parent_chd.opened() ? &input_parent_chd : nullptr); - if (err != CHDERR_NONE) - report_error(1, "Error opening CHD file (%s): %s", input_chd_str->second->c_str(), chd_file::error_string(err)); + std::error_condition err = input_chd.open(*input_chd_str->second, writeable, input_parent_chd.opened() ? &input_parent_chd : nullptr); + if (err) + report_error(1, "Error opening CHD file (%s): %s", *input_chd_str->second, err.message()); } } @@ -1027,38 +1185,80 @@ static void parse_input_chd_parameters(const parameters_t ¶ms, chd_file &inp // parameters in a standard way //------------------------------------------------- -static void parse_input_start_end(const parameters_t ¶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); } @@ -1068,13 +1268,13 @@ static void parse_input_start_end(const parameters_t ¶ms, uint64_t logical_s // unless --force is specified //------------------------------------------------- -static void check_existing_output_file(const parameters_t ¶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()) { util::core_file::ptr file; - osd_file::error filerr = util::core_file::open(filename, OPEN_FLAG_READ, file); - if (filerr == osd_file::error::NONE) + std::error_condition const filerr = util::core_file::open(filename, OPEN_FLAG_READ, file); + if (!filerr) { file.reset(); report_error(1, "Error: file already exists (%s)\nUse --force (or -f) to force overwriting", filename); @@ -1088,22 +1288,23 @@ static void check_existing_output_file(const parameters_t ¶ms, const char *f // standard set of output CHD parameters //------------------------------------------------- -static std::string *parse_output_chd_parameters(const parameters_t ¶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()) { - chd_error err = output_parent_chd.open(output_chd_parent_str->second->c_str()); - if (err != CHDERR_NONE) - report_error(1, "Error opening parent CHD file (%s): %s", output_chd_parent_str->second->c_str(), chd_file::error_string(err)); + std::error_condition err = output_parent_chd.open(*output_chd_parent_str->second); + if (err) + report_error(1, "Error opening parent CHD file (%s): %s", *output_chd_parent_str->second, err.message()); } // 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; } @@ -1112,17 +1313,32 @@ static std::string *parse_output_chd_parameters(const parameters_t ¶ms, chd_ // parameter in a standard way //------------------------------------------------- -static void parse_hunk_size(const parameters_t ¶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; } @@ -1131,15 +1347,18 @@ static void parse_hunk_size(const parameters_t ¶ms, uint32_t required_granul // compression parameter string //------------------------------------------------- -static void parse_compression(const parameters_t ¶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; @@ -1151,10 +1370,10 @@ static void parse_compression(const parameters_t ¶ms, chd_codec_type compres { std::string name(*compression_str->second, start, (end == -1) ? -1 : end - start); if (name.length() != 4) - report_error(1, "Invalid compressor '%s' specified", name.c_str()); + report_error(1, "Invalid compressor '%s' specified", name); chd_codec_type type = CHD_MAKE_TAG(name[0], name[1], name[2], name[3]); if (!chd_codec_list::codec_exists(type)) - report_error(1, "Invalid compressor '%s' specified", name.c_str()); + report_error(1, "Invalid compressor '%s' specified", name); compression[index++] = type; if (end == -1) break; @@ -1172,7 +1391,7 @@ static void parse_compression(const parameters_t ¶ms, chd_codec_type compres // command //------------------------------------------------- -static void parse_numprocessors(const parameters_t ¶ms) +static void parse_numprocessors(const parameters_map ¶ms) { auto numprocessors_str = params.find(OPTION_NUMPROCESSORS); if (numprocessors_str == params.end()) @@ -1218,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 //------------------------------------------------- @@ -1228,16 +1490,16 @@ static void compress_common(chd_file_compressor &chd) // loop until done double complete, ratio; - chd_error err; - while ((err = chd.compress_continue(complete, ratio)) == CHDERR_WALKING_PARENT || err == CHDERR_COMPRESSING) - if (err == CHDERR_WALKING_PARENT) + std::error_condition err; + while ((err = chd.compress_continue(complete, ratio)) == chd_file::error::WALKING_PARENT || err == chd_file::error::COMPRESSING) + if (err == chd_file::error::WALKING_PARENT) progress(false, "Examining parent, %.1f%% complete... \r", 100.0 * complete); else progress(false, "Compressing, %.1f%% complete... (ratio=%.1f%%) \r", 100.0 * complete, 100.0 * ratio); // handle errors - if (err != CHDERR_NONE) - report_error(1, "Error during compression: %-40s", chd_file::error_string(err)); + if (err) + report_error(1, "Error during compression: %-40s", err.message()); // final progress update progress(true, "Compression complete ... final ratio = %.1f%% \n", 100.0 * ratio); @@ -1249,81 +1511,39 @@ 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_track_info &info, const char *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 CD_TRACK_MODE1: - mode = 4; - size = 2048; - break; - - case CD_TRACK_MODE1_RAW: - mode = 4; - size = 2352; - break; - - case CD_TRACK_MODE2: - mode = 4; - size = 2336; - break; - - case CD_TRACK_MODE2_FORM1: - mode = 4; - size = 2048; - break; - - case CD_TRACK_MODE2_FORM2: - mode = 4; - size = 2324; - break; - - case CD_TRACK_MODE2_FORM_MIX: - mode = 4; - size = 2336; - break; - - case CD_TRACK_MODE2_RAW: - mode = 4; - size = 2352; - break; - - case CD_TRACK_AUDIO: - mode = 0; - size = 2352; - break; - } - bool needquote = strchr(filename, ' ') != nullptr; - file.printf("%d %d %d %d %s%s%s %d\n", tracknum+1, frameoffs, mode, size, needquote?"\"":"", filename, needquote?"\"":"", discoffs); + 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, 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 std::string tempstr; switch (info.trktype) { - case CD_TRACK_MODE1: - case CD_TRACK_MODE1_RAW: + case cdrom_file::CD_TRACK_MODE1: + case cdrom_file::CD_TRACK_MODE1_RAW: tempstr = string_format("MODE1/%04d", info.datasize); break; - case CD_TRACK_MODE2: - case CD_TRACK_MODE2_FORM1: - case CD_TRACK_MODE2_FORM2: - case CD_TRACK_MODE2_FORM_MIX: - case CD_TRACK_MODE2_RAW: + case cdrom_file::CD_TRACK_MODE2: + case cdrom_file::CD_TRACK_MODE2_FORM1: + case cdrom_file::CD_TRACK_MODE2_FORM2: + case cdrom_file::CD_TRACK_MODE2_FORM_MIX: + case cdrom_file::CD_TRACK_MODE2_RAW: tempstr = string_format("MODE2/%04d", info.datasize); break; - case CD_TRACK_AUDIO: + case cdrom_file::CD_TRACK_AUDIO: tempstr.assign("AUDIO"); break; } @@ -1356,22 +1576,19 @@ void output_track_metadata(int mode, util::core_file &file, int tracknum, const // non-CUE mode else if (mode == MODE_NORMAL) { - // header on the first track - if (tracknum == 0) - file.printf("CD_ROM\n\n\n"); file.printf("// Track %d\n", tracknum + 1); // write out the track type std::string modesubmode; - if (info.subtype != CD_SUB_NONE) - modesubmode = string_format("%s %s", cdrom_get_type_string(info.trktype), cdrom_get_subtype_string(info.subtype)); + if (info.subtype != cdrom_file::CD_SUB_NONE) + modesubmode = string_format("%s %s", cdrom_file::get_type_string(info.trktype), cdrom_file::get_subtype_string(info.subtype)); else - modesubmode = string_format("%s", cdrom_get_type_string(info.trktype)); + modesubmode = string_format("%s", cdrom_file::get_type_string(info.trktype)); file.printf("TRACK %s\n", modesubmode); // write out the attributes file.printf("NO COPY\n"); - if (info.trktype == CD_TRACK_AUDIO) + if (info.trktype == cdrom_file::CD_TRACK_AUDIO) { file.printf("NO PRE_EMPHASIS\n"); file.printf("TWO_CHANNEL_AUDIO\n"); @@ -1381,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) @@ -1401,7 +1617,7 @@ void output_track_metadata(int mode, util::core_file &file, int tracknum, const // a drive image //------------------------------------------------- -static void do_info(parameters_t ¶ms) +static void do_info(parameters_map ¶ms) { bool verbose = params.find(OPTION_VERBOSE) != params.end(); // parse out input files @@ -1410,34 +1626,36 @@ static void do_info(parameters_t ¶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()); // output cmpression and size information chd_codec_type compression[4] = { input_chd.compression(0), input_chd.compression(1), input_chd.compression(2), input_chd.compression(3) }; - 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(static_cast<util::core_file &>(input_chd).size()).c_str()); + uint64_t filesize = 0; + input_chd.file().length(filesize); + 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(static_cast<util::core_file &>(input_chd).size()) / 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; @@ -1447,8 +1665,8 @@ static void do_info(parameters_t ¶ms) // get the indexed metadata item; stop when we hit an error chd_metadata_tag metatag; uint8_t metaflags; - chd_error err = input_chd.read_metadata(CHDMETATAG_WILDCARD, index, buffer, metatag, metaflags); - if (err != CHDERR_NONE) + std::error_condition err = input_chd.read_metadata(CHDMETATAG_WILDCARD, index, buffer, metatag, metaflags); + if (err) break; // determine our index @@ -1470,18 +1688,18 @@ static void do_info(parameters_t ¶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 @@ -1493,9 +1711,9 @@ static void do_info(parameters_t ¶ms) // get info on this hunk chd_codec_type codec; uint32_t compbytes; - chd_error err = input_chd.hunk_info(hunknum, codec, compbytes); - if (err != CHDERR_NONE) - report_error(1, "Error getting info on hunk %d: %s", hunknum, chd_file::error_string(err)); + std::error_condition err = input_chd.hunk_info(hunknum, codec, compbytes); + if (err) + report_error(1, "Error getting info on hunk %d: %s", hunknum, err.message()); // decode into our data if (codec > CHD_CODEC_MINI) @@ -1505,18 +1723,18 @@ static void do_info(parameters_t ¶ms) codec = CHD_CODEC_MINI + 1 + comptype; break; } - if (codec > ARRAY_LENGTH(compression_types)) - codec = ARRAY_LENGTH(compression_types) - 1; + if (codec >= std::size(compression_types)) + codec = std::size(compression_types) - 1; // count stats compression_types[codec]++; } // output the stats - printf("\n"); - printf(" Hunks Percent Name\n"); - printf("---------- ------- ------------------------------------\n"); - for (int comptype = 0; comptype < ARRAY_LENGTH(compression_types); comptype++) + 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) { // determine the name @@ -1535,8 +1753,8 @@ static void do_info(parameters_t ¶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); } @@ -1545,17 +1763,17 @@ static void do_info(parameters_t ¶ms) //------------------------------------------------- -// do_verify - validate the SHA1 on a CHD +// do_verify - validate the SHA-1 on a CHD //------------------------------------------------- -static void do_verify(parameters_t ¶ms) +static void do_verify(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); - // 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(); @@ -1573,9 +1791,9 @@ static void do_verify(parameters_t ¶ms) // determine how much to read uint32_t bytes_to_read = (std::min<uint64_t>)(buffer.size(), input_chd.logical_bytes() - offset); - chd_error err = input_chd.read_bytes(offset, &buffer[0], bytes_to_read); - if (err != CHDERR_NONE) - report_error(1, "Error reading CHD file (%s): %s", params.find(OPTION_INPUT)->second->c_str(), chd_file::error_string(err)); + 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()); // add to the checksum rawsha1.append(&buffer[0], bytes_to_read); @@ -1586,36 +1804,41 @@ static void do_verify(parameters_t ¶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"); } } } @@ -1628,25 +1851,14 @@ static void do_verify(parameters_t ¶ms) // image from a raw file //------------------------------------------------- -static void do_create_raw(parameters_t ¶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()) - { - osd_file::error filerr = util::core_file::open(*input_file_str->second, OPEN_FLAG_READ, input_file); - if (filerr != osd_file::error::NONE) - report_error(1, "Unable to open file (%s)", input_file_str->second->c_str()); - } + 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; @@ -1654,49 +1866,49 @@ static void do_create_raw(parameters_t ¶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; - parse_input_start_end(params, input_file->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()); - if (input_start != 0 || input_end != input_file->size()) + 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)); - chd_error 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 != CHDERR_NONE) - report_error(1, "Error creating CHD file (%s): %s", output_chd_str->c_str(), chd_file::error_string(err)); + 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()) @@ -1708,9 +1920,7 @@ static void do_create_raw(parameters_t ¶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; } } @@ -1721,80 +1931,96 @@ static void do_create_raw(parameters_t ¶ms) // disk image from a raw file //------------------------------------------------- -static void do_create_hd(parameters_t ¶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()) - { - osd_file::error filerr = util::core_file::open(*input_file_str->second, OPEN_FLAG_READ, input_file); - if (filerr != osd_file::error::NONE) - report_error(1, "Unable to open file (%s)", input_file_str->second->c_str()); - } + 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) { - parse_input_start_end(params, input_file->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()) @@ -1803,110 +2029,92 @@ static void do_create_hd(parameters_t ¶ms) if (ident_str != params.end()) { // load the file - osd_file::error filerr = util::core_file::load(ident_str->second->c_str(), identdata); - if (filerr != osd_file::error::NONE) - report_error(1, "Error reading ident file (%s)", ident_str->second->c_str()); + std::error_condition const filerr = util::core_file::load(*ident_str->second, identdata); + if (filerr) + report_error(1, "Error reading ident file (%s): %s", *ident_str->second, filerr.message()); // must be at least 14 bytes; extract CHS data from there if (identdata.size() < 14) - report_error(1, "Ident file '%s' is invalid (too short)", ident_str->second->c_str()); - cylinders = (identdata[3] << 8) | identdata[2]; - heads = (identdata[7] << 8) | identdata[6]; - sectors = (identdata[13] << 8) | identdata[12]; + report_error(1, "Ident file '%s' is invalid (too short)", *ident_str->second); + cylinders = get_u16le(&identdata[2]); + heads = get_u16le(&identdata[6]); + 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 >= ARRAY_LENGTH(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) { std::string metadata; - if (output_parent.read_metadata(HARD_DISK_METADATA_TAG, 0, metadata) != CHDERR_NONE) + if (output_parent.read_metadata(HARD_DISK_METADATA_TAG, 0, metadata)) report_error(1, "Unable to find hard disk metadata in parent CHD"); if (sscanf(metadata.c_str(), HARD_DISK_METADATA_FORMAT, &cylinders, &heads, §ors, §or_size) != 4) report_error(1, "Error parsing hard disk metadata in parent CHD"); } // 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) { - printf("Input file: %s\n", input_file_str->second->c_str()); - if (input_start != 0 || input_end != input_file->size()) + 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)); - chd_error 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 != CHDERR_NONE) - report_error(1, "Error creating CHD file (%s): %s", output_chd_str->c_str(), chd_file::error_string(err)); + 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 != CHDERR_NONE) - report_error(1, "Error adding hard disk metadata: %s", chd_file::error_string(err)); + if (err) + report_error(1, "Error adding hard disk metadata: %s", err.message()); // write the ident if present if (!identdata.empty()) { err = chd->write_metadata(HARD_DISK_IDENT_METADATA_TAG, 0, identdata); - if (err != CHDERR_NONE) - report_error(1, "Error adding hard disk metadata: %s", chd_file::error_string(err)); + if (err) + report_error(1, "Error adding hard disk metadata: %s", err.message()); } // compress it generically @@ -1916,9 +2124,7 @@ static void do_create_hd(parameters_t ¶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; } } @@ -1929,87 +2135,144 @@ static void do_create_hd(parameters_t ¶ms) // image from a raw file //------------------------------------------------- -static void do_create_cd(parameters_t ¶ms) +static void do_create_cd(parameters_map ¶ms) { // process input file - chdcd_track_input_info track_info; - cdrom_toc toc = { 0 }; + cdrom_file::track_input_info track_info; + cdrom_file::toc toc = { 0 }; auto input_file_str = params.find(OPTION_INPUT); if (input_file_str != params.end()) { - chd_error err = chdcd_parse_toc(input_file_str->second->c_str(), toc, track_info); - if (err != CHDERR_NONE) - report_error(1, "Error parsing input file (%s: %s)\n", input_file_str->second->c_str(), chd_file::error_string(err)); + std::error_condition err = cdrom_file::parse_toc(*input_file_str->second, toc, track_info); + if (err) + report_error(1, "Error parsing input file (%s: %s)\n", *input_file_str->second, err.message()); } // 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() : CD_FRAMES_PER_HUNK * CD_FRAME_SIZE; - parse_hunk_size(params, CD_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++) { - cdrom_track_info &trackinfo = toc.tracks[tracknum]; - int padded = (trackinfo.frames + CD_TRACK_PADDING - 1) / CD_TRACK_PADDING; - trackinfo.extraframes = padded * CD_TRACK_PADDING - trackinfo.frames; + cdrom_file::track_info &trackinfo = toc.tracks[tracknum]; + int padded = (trackinfo.frames + cdrom_file::TRACK_PADDING - 1) / cdrom_file::TRACK_PADDING; + trackinfo.extraframes = padded * cdrom_file::TRACK_PADDING - trackinfo.frames; origtotalsectors += trackinfo.frames; totalsectors += trackinfo.frames + trackinfo.extraframes; } // 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) * CD_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); - chd_error err; - if (output_parent.opened()) - err = chd->create(output_chd_str->c_str(), uint64_t(totalsectors) * uint64_t(CD_FRAME_SIZE), hunk_size, compression, output_parent); - else - err = chd->create(output_chd_str->c_str(), uint64_t(totalsectors) * uint64_t(CD_FRAME_SIZE), hunk_size, CD_FRAME_SIZE, compression); - if (err != CHDERR_NONE) - report_error(1, "Error creating CHD file (%s): %s", output_chd_str->c_str(), chd_file::error_string(err)); + 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_write_metadata(chd, &toc); - if (err != CHDERR_NONE) - report_error(1, "Error adding CD metadata: %s", chd_file::error_string(err)); + 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; + } +} + + +//------------------------------------------------- +// do_create_dvd - create a new compressed dvd +// image from a raw file +//------------------------------------------------- + +static void do_create_dvd(parameters_map ¶ms) +{ + // process input file + auto [input_file, input_file_str] = open_input_file(params); + + // process output CHD + chd_file 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 + 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]; + parse_compression(params, s_default_hd_compression, output_parent, compression); // No reason to be different than HD for compression + + // process numprocessors + parse_numprocessors(params); + + // print some info + util::stream_format(std::cout, "Output CHD: %s\n", *output_chd_str); + if (output_parent.opened()) + 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 + 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 + const std::error_condition err = chd->write_metadata(DVD_METADATA_TAG, 0, ""); + if (err) + report_error(1, "Error adding DVD metadata: %s", err.message()); + + // compress it generically + compress_common(*chd); + } + catch (...) + { + // delete the output file + osd_file::remove(*output_chd_str); throw; } } @@ -2020,7 +2283,7 @@ static void do_create_cd(parameters_t ¶ms) // input AVI file and metadata //------------------------------------------------- -static void do_create_ld(parameters_t ¶ms) +static void do_create_ld(parameters_map ¶ms) { // process input file avi_file::ptr input_file; @@ -2029,18 +2292,16 @@ static void do_create_ld(parameters_t ¶ms) { avi_file::error avierr = avi_file::open(*input_file_str->second, input_file); if (avierr != avi_file::error::NONE) - report_error(1, "Error opening AVI file (%s): %s\n", input_file_str->second->c_str(), avi_file::error_string(avierr)); + report_error(1, "Error opening AVI file (%s): %s\n", *input_file_str->second, avi_file::error_string(avierr)); } const avi_file::movie_info &aviinfo = input_file->get_movie_info(); // 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; @@ -2065,13 +2326,11 @@ static void do_create_ld(parameters_t ¶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"); @@ -2080,42 +2339,36 @@ static void do_create_ld(parameters_t ¶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); - chd_error 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 != CHDERR_NONE) - report_error(1, "Error creating CHD file (%s): %s", output_chd_str->c_str(), chd_file::error_string(err)); + 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 != CHDERR_NONE) - report_error(1, "Error adding AV metadata: %s\n", chd_file::error_string(err)); + if (err) + report_error(1, "Error adding AV metadata: %s\n", err.message()); // create the compressor and then run it generically compress_common(*chd); @@ -2124,29 +2377,58 @@ static void do_create_ld(parameters_t ¶ms) if (info.height == 524/2 || info.height == 624/2) { err = chd->write_metadata(AV_LD_METADATA_TAG, 0, chd->ldframedata(), 0); - if (err != CHDERR_NONE) - report_error(1, "Error adding AVLD metadata: %s\n", chd_file::error_string(err)); + 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 //------------------------------------------------- -static void do_copy(parameters_t ¶ms) +static void do_copy(parameters_map ¶ms) { // parse out input files chd_file input_parent_chd; @@ -2154,78 +2436,56 @@ static void do_copy(parameters_t ¶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) == CHDERR_NONE) - memcpy(compression, s_default_hd_compression, sizeof(compression)); - else if (input_chd.read_metadata(AV_METADATA_TAG, 0, metadata) == CHDERR_NONE) - memcpy(compression, s_default_ld_compression, sizeof(compression)); - else if (input_chd.read_metadata(CDROM_OLD_METADATA_TAG, 0, metadata) == CHDERR_NONE || - input_chd.read_metadata(CDROM_TRACK_METADATA_TAG, 0, metadata) == CHDERR_NONE || - input_chd.read_metadata(CDROM_TRACK_METADATA2_TAG, 0, metadata) == CHDERR_NONE || - input_chd.read_metadata(GDROM_OLD_METADATA_TAG, 0, metadata) == CHDERR_NONE || - input_chd.read_metadata(GDROM_TRACK_METADATA_TAG, 0, metadata) == CHDERR_NONE) - 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); - chd_error 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 != CHDERR_NONE) - report_error(1, "Error creating CHD file (%s): %s", output_chd_str->c_str(), chd_file::error_string(err)); + 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; uint32_t index = 0; bool redo_cd = false; bool cdda_swap = false; - for (err = input_chd.read_metadata(CHDMETATAG_WILDCARD, index++, metadata, metatag, metaflags); err == CHDERR_NONE; err = input_chd.read_metadata(CHDMETATAG_WILDCARD, index++, metadata, metatag, metaflags)) + for (err = input_chd.read_metadata(CHDMETATAG_WILDCARD, index++, metadata, metatag, metaflags); !err; err = input_chd.read_metadata(CHDMETATAG_WILDCARD, index++, metadata, metatag, metaflags)) { // if this is an old CD-CHD tag, note that we want to re-do it if (metatag == CDROM_OLD_METADATA_TAG || metatag == CDROM_TRACK_METADATA_TAG) @@ -2242,35 +2502,29 @@ static void do_copy(parameters_t ¶ms) // otherwise, clone it err = chd->write_metadata(metatag, CHDMETAINDEX_APPEND, metadata, metaflags); - if (err != CHDERR_NONE) - report_error(1, "Error writing cloned metadata: %s", chd_file::error_string(err)); + if (err) + report_error(1, "Error writing cloned metadata: %s", err.message()); } // if we need to re-do the CD metadata, do it now if (redo_cd) { - cdrom_file *cdrom = cdrom_open(&input_chd); - if (cdrom == nullptr) - report_error(1, "Error upgrading CD metadata"); - const cdrom_toc *toc = cdrom_get_toc(cdrom); - err = cdrom_write_metadata(chd, toc); - if (err != CHDERR_NONE) - report_error(1, "Error writing upgraded CD metadata: %s", chd_file::error_string(err)); + cdrom = std::make_unique<cdrom_file>(&input_chd); + const cdrom_file::toc &toc = cdrom->get_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) - chd->m_toc = toc; + chd->m_toc = &toc; } // 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; } } @@ -2281,7 +2535,7 @@ static void do_copy(parameters_t ¶ms) // CHD image //------------------------------------------------- -static void do_extract_raw(parameters_t ¶ms) +static void do_extract_raw(parameters_map ¶ms) { // parse out input files chd_file input_parent_chd; @@ -2289,22 +2543,20 @@ static void do_extract_raw(parameters_t ¶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 @@ -2312,9 +2564,9 @@ static void do_extract_raw(parameters_t ¶ms) try { // process output file - osd_file::error filerr = util::core_file::open(*output_file_str->second, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, output_file); - if (filerr != osd_file::error::NONE) - report_error(1, "Unable to open file (%s)", output_file_str->second->c_str()); + 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()); @@ -2324,14 +2576,14 @@ static void do_extract_raw(parameters_t ¶ms) // determine how much to read uint32_t bytes_to_read = (std::min<uint64_t>)(buffer.size(), input_end - offset); - chd_error err = input_chd.read_bytes(offset, &buffer[0], bytes_to_read); - if (err != CHDERR_NONE) - report_error(1, "Error reading CHD file (%s): %s", params.find(OPTION_INPUT)->second->c_str(), chd_file::error_string(err)); + 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 - uint32_t count = output_file->write(&buffer[0], bytes_to_read); - if (count != bytes_to_read) - report_error(1, "Error writing to file; check disk space (%s)", output_file_str->second->c_str()); + 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 offset += bytes_to_read; @@ -2339,7 +2591,7 @@ static void do_extract_raw(parameters_t ¶ms) // finish up output_file.reset(); - printf("Extraction complete \n"); + util::stream_format(std::cout, "Extraction complete \n"); } catch (...) { @@ -2359,7 +2611,7 @@ static void do_extract_raw(parameters_t ¶ms) // CHD image //------------------------------------------------- -static void do_extract_cd(parameters_t ¶ms) +static void do_extract_cd(parameters_map ¶ms) { // parse out input files chd_file input_parent_chd; @@ -2367,123 +2619,320 @@ static void do_extract_cd(parameters_t ¶ms) parse_input_chd_parameters(params, input_chd, input_parent_chd); // further process input file - cdrom_file *cdrom = cdrom_open(&input_chd); - if (cdrom == nullptr) - report_error(1, "Unable to recognize CHD file as a CD"); - const cdrom_toc *toc = cdrom_get_toc(cdrom); + cdrom_file *cdrom = new cdrom_file(&input_chd); + const cdrom_file::toc &toc = cdrom->get_toc(); // 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()); - char basename[128]; - strncpy(basename, default_name.c_str(), 127); - 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; + // 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()); - if (output_file_str->second->find(".cue") != -1) + uint64_t total_bytes = 0; + for (int tracknum = 0; tracknum < toc.numtrks; tracknum++) { - mode = MODE_CUEBIN; + // 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); } - else if (output_file_str->second->find(".gdi") != -1) + + // GDI must start with the # of tracks + if (mode == MODE_GDI) { - mode = MODE_GDI; + output_toc_file->printf("%d\n", toc.numtrks); } + else if (mode == MODE_NORMAL) + { + bool mode1 = false; + bool mode2 = false; + bool cdda = false; - // process output file - osd_file::error filerr = util::core_file::open(*output_file_str->second, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_NO_BOM, output_toc_file); - if (filerr != osd_file::error::NONE) - report_error(1, "Unable to open file (%s)", output_file_str->second->c_str()); + for (int tracknum = 0; tracknum < toc.numtrks; tracknum++) + { + switch (toc.tracks[tracknum].trktype) + { + case cdrom_file::CD_TRACK_MODE1: + case cdrom_file::CD_TRACK_MODE1_RAW: + mode1 = true; + break; - // 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 != osd_file::error::NONE) - report_error(1, "Unable to open file (%s)", output_bin_file_str->c_str()); - } + case cdrom_file::CD_TRACK_MODE2: + case cdrom_file::CD_TRACK_MODE2_FORM1: + case cdrom_file::CD_TRACK_MODE2_FORM2: + case cdrom_file::CD_TRACK_MODE2_FORM_MIX: + case cdrom_file::CD_TRACK_MODE2_RAW: + mode2 = true; + break; - // determine total frames - uint64_t total_bytes = 0; - for (int tracknum = 0; tracknum < toc->numtrks; tracknum++) - total_bytes += toc->tracks[tracknum].frames * (toc->tracks[tracknum].datasize + toc->tracks[tracknum].subsize); + case cdrom_file::CD_TRACK_AUDIO: + cdda = true; + break; + } + } - // GDI must start with the # of tracks - if (mode == MODE_GDI) + if (mode2) + output_toc_file->printf("CD_ROM_XA\n\n\n"); + else if (cdda && !mode1) + output_toc_file->printf("CD_DA\n\n\n"); + else + output_toc_file->printf("CD_ROM\n\n\n"); + } + + if (cdrom->is_gdrom() && mode == MODE_CUEBIN) { - output_toc_file->printf("%d\n", toc->numtrks); + // 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) + for (int tracknum = 0; tracknum < toc.numtrks; tracknum++) + { + if (track_filenames[tracknum] != trackbin_name) { - char temp[11]; - sprintf(temp, "%02d", tracknum+1); - trackbin_name.append(temp); - if (toc->tracks[tracknum].trktype == CD_TRACK_AUDIO) - trackbin_name.append(".raw"); - else - trackbin_name.append(".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 != osd_file::error::NONE) - report_error(1, "Unable to open file (%s)", trackbin_name.c_str()); + 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_track_info &trackinfo = toc->tracks[tracknum]; - if (mode == MODE_GDI) - { - output_track_metadata(mode, *output_toc_file, tracknum, trackinfo, core_filename_extract_base(trackbin_name).c_str(), discoffs, outputoffs); - } - else + if (cdrom->is_gdrom() && mode == MODE_CUEBIN) { - output_track_metadata(mode, *output_toc_file, tracknum, trackinfo, core_filename_extract_base(*output_bin_file_str).c_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 != CD_SUB_NONE) ? trackinfo.subsize : 0); - if (trackinfo.subtype != CD_SUB_NONE && ((mode == MODE_CUEBIN) || (mode == MODE_GDI))) + 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; } @@ -2492,40 +2941,53 @@ static void do_extract_cd(parameters_t ¶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, cdrom_get_track_start_phys(cdrom, 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 == 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 != CD_SUB_NONE && (mode == MODE_NORMAL)) + if (toc.tracks[trk].subtype != cdrom_file::CD_SUB_NONE && (mode == MODE_NORMAL)) { - cdrom_read_subcode(cdrom, cdrom_get_track_start_phys(cdrom, 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); - uint32_t byteswritten = output_bin_file->write(&buffer[0], bufferoffs); - if (byteswritten != bufferoffs) - report_error(1, "Error writing frame %d to file (%s): %s\n", frame, output_file_str->second->c_str(), chd_file::error_string(CHDERR_WRITE_ERROR)); + 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; } @@ -2537,26 +2999,29 @@ static void do_extract_cd(parameters_t ¶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_ld - extract an AVI file from a // CHD image //------------------------------------------------- -static void do_extract_ld(parameters_t ¶ms) +static void do_extract_ld(parameters_map ¶ms) { // parse out input files chd_file input_parent_chd; @@ -2565,8 +3030,8 @@ static void do_extract_ld(parameters_t ¶ms) // read core metadata std::string metadata; - chd_error err = input_chd.read_metadata(AV_METADATA_TAG, 0, metadata); - if (err != CHDERR_NONE) + std::error_condition err = input_chd.read_metadata(AV_METADATA_TAG, 0, metadata); + if (err) report_error(1, "Unable to find A/V metadata in the input CHD"); // parse the metadata @@ -2594,15 +3059,13 @@ static void do_extract_ld(parameters_t ¶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; // build up the movie info avi_file::movie_info info; - info.video_format = FORMAT_YUY2; + info.video_format = avi_file::FORMAT_YUY2; info.video_timescale = fps_times_1million / interlace_factor; info.video_sampletime = 1000000; info.video_width = width; @@ -2618,15 +3081,15 @@ static void do_extract_ld(parameters_t ¶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 @@ -2636,15 +3099,17 @@ static void do_extract_ld(parameters_t ¶ms) // process output file avi_file::error avierr = avi_file::create(*output_file_str->second, info, output_file); if (avierr != avi_file::error::NONE) - report_error(1, "Unable to open file (%s)", output_file_str->second->c_str()); + report_error(1, "Unable to open file (%s)", *output_file_str->second); // create the codec configuration - avhuff_decompress_config avconfig; + avhuff_decoder::config avconfig; + bitmap_yuy16 avvideo; std::vector<int16_t> audio_data[16]; uint32_t actsamples; + avconfig.video = &avvideo; avconfig.maxsamples = max_samples_per_frame; avconfig.actsamples = &actsamples; - for (int chnum = 0; chnum < ARRAY_LENGTH(audio_data); chnum++) + for (int chnum = 0; chnum < std::size(audio_data); chnum++) { audio_data[chnum].resize(std::max(1U,max_samples_per_frame)); avconfig.audio[chnum] = &audio_data[chnum][0]; @@ -2657,15 +3122,16 @@ static void do_extract_ld(parameters_t ¶ms) progress(framenum == input_start, "Extracting, %.1f%% complete... \r", 100.0 * double(framenum - input_start) / double(input_end - input_start)); // set up the fake bitmap for this frame - avconfig.video.wrap(&fullbitmap.pix(framenum % interlace_factor), fullbitmap.width(), fullbitmap.height() / interlace_factor, fullbitmap.rowpixels() * interlace_factor); + avvideo.wrap(&fullbitmap.pix(framenum % interlace_factor), fullbitmap.width(), fullbitmap.height() / interlace_factor, fullbitmap.rowpixels() * interlace_factor); input_chd.codec_configure(CHD_CODEC_AVHUFF, AVHUFF_CODEC_DECOMPRESS_CONFIG, &avconfig); // read the hunk into the buffers - chd_error err = input_chd.read_hunk(framenum, nullptr); - if (err != CHDERR_NONE) + std::error_condition err = input_chd.codec_process_hunk(framenum); + if (err) { - uint64_t filepos = static_cast<util::core_file &>(input_chd).tell(); - report_error(1, "Error reading hunk %d at offset %d from CHD file (%s): %s\n", framenum, filepos, params.find(OPTION_INPUT)->second->c_str(), chd_file::error_string(err)); + uint64_t filepos = ~uint64_t(0); + input_chd.file().tell(filepos); + report_error(1, "Error reading hunk %d at offset %d from CHD file (%s): %s\n", framenum, filepos, *params.find(OPTION_INPUT)->second, err.message()); } // write audio @@ -2673,7 +3139,7 @@ static void do_extract_ld(parameters_t ¶ms) { avi_file::error avierr = output_file->append_sound_samples(chnum, avconfig.audio[chnum], actsamples, 0); if (avierr != avi_file::error::NONE) - report_error(1, "Error writing samples for hunk %d to file (%s): %s\n", framenum, output_file_str->second->c_str(), avi_file::error_string(avierr)); + report_error(1, "Error writing samples for hunk %d to file (%s): %s\n", framenum, *output_file_str->second, avi_file::error_string(avierr)); } // write video @@ -2681,13 +3147,13 @@ static void do_extract_ld(parameters_t ¶ms) { avi_file::error avierr = output_file->append_video_frame(fullbitmap); if (avierr != avi_file::error::NONE) - report_error(1, "Error writing video for hunk %d to file (%s): %s\n", framenum, output_file_str->second->c_str(), avi_file::error_string(avierr)); + report_error(1, "Error writing video for hunk %d to file (%s): %s\n", framenum, *output_file_str->second, avi_file::error_string(avierr)); } } // close and return output_file.reset(); - printf("Extraction complete \n"); + util::stream_format(std::cout, "Extraction complete \n"); } catch (...) { @@ -2704,7 +3170,7 @@ static void do_extract_ld(parameters_t ¶ms) // file //------------------------------------------------- -static void do_add_metadata(parameters_t ¶ms) +static void do_add_metadata(parameters_map ¶ms) { // parse out input files chd_file input_parent_chd; @@ -2741,9 +3207,9 @@ static void do_add_metadata(parameters_t ¶ms) std::vector<uint8_t> file; if (file_str != params.end()) { - osd_file::error filerr = util::core_file::load(file_str->second->c_str(), file); - if (filerr != osd_file::error::NONE) - report_error(1, "Error reading metadata file (%s)", file_str->second->c_str()); + std::error_condition const filerr = util::core_file::load(*file_str->second, file); + if (filerr) + report_error(1, "Error reading metadata file (%s): %s", *file_str->second, filerr.message()); } // make sure we have one or the other @@ -2758,24 +3224,24 @@ static void do_add_metadata(parameters_t ¶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 - chd_error err; + std::error_condition err; if (text_str != params.end()) err = input_chd.write_metadata(tag, index, text, flags); else err = input_chd.write_metadata(tag, index, file, flags); - if (err != CHDERR_NONE) - report_error(1, "Error adding metadata: %s", chd_file::error_string(err)); + if (err) + report_error(1, "Error adding metadata: %s", err.message()); else - printf("Metadata added\n"); + util::stream_format(std::cout, "Metadata added\n"); } @@ -2783,7 +3249,7 @@ static void do_add_metadata(parameters_t ¶ms) // do_del_metadata - remove metadata from a CHD //------------------------------------------------- -static void do_del_metadata(parameters_t ¶ms) +static void do_del_metadata(parameters_map ¶ms) { // parse out input files chd_file input_parent_chd; @@ -2806,16 +3272,16 @@ static void do_del_metadata(parameters_t ¶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 - chd_error err = input_chd.delete_metadata(tag, index); - if (err != CHDERR_NONE) - report_error(1, "Error removing metadata: %s", chd_file::error_string(err)); + 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"); } @@ -2823,7 +3289,7 @@ static void do_del_metadata(parameters_t ¶ms) // do_dump_metadata - dump metadata from a CHD //------------------------------------------------- -static void do_dump_metadata(parameters_t ¶ms) +static void do_dump_metadata(parameters_map ¶ms) { // parse out input files chd_file input_parent_chd; @@ -2833,7 +3299,7 @@ static void do_dump_metadata(parameters_t ¶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('?','?','?','?'); @@ -2852,9 +3318,9 @@ static void do_dump_metadata(parameters_t ¶ms) // write the metadata std::vector<uint8_t> buffer; - chd_error err = input_chd.read_metadata(tag, index, buffer); - if (err != CHDERR_NONE) - report_error(1, "Error reading metadata: %s", chd_file::error_string(err)); + std::error_condition err = input_chd.read_metadata(tag, index, buffer); + if (err) + report_error(1, "Error reading metadata: %s", err.message()); // catch errors so we can close & delete the output file util::core_file::ptr output_file; @@ -2863,23 +3329,28 @@ static void do_dump_metadata(parameters_t ¶ms) // create the file if (output_file_str != params.end()) { - osd_file::error filerr = util::core_file::open(*output_file_str->second, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, output_file); - if (filerr != osd_file::error::NONE) - report_error(1, "Unable to open file (%s)", output_file_str->second->c_str()); + std::error_condition filerr; + + 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()); // output the metadata - uint32_t count = output_file->write(&buffer[0], buffer.size()); - if (count != buffer.size()) - report_error(1, "Error writing file (%s)", output_file_str->second->c_str()); + size_t count; + std::tie(filerr, count) = write(*output_file, &buffer[0], buffer.size()); + if (!filerr) + filerr = output_file->flush(); + 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())); } - - // flush to stdout else { + // flush to stdout + // FIXME: check for errors fwrite(&buffer[0], 1, buffer.size(), stdout); fflush(stdout); } @@ -2895,18 +3366,18 @@ static void do_dump_metadata(parameters_t ¶ms) //------------------------------------------------- -// do_dump_metadata - dump metadata from a CHD +// do_list_templates - list hard drive templates //------------------------------------------------- -static void do_list_templates(parameters_t ¶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 < ARRAY_LENGTH(s_hd_templates); id++) + 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, @@ -2926,59 +3397,61 @@ static void do_list_templates(parameters_t ¶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 (argc < 2) - return print_help(argv[0]); + if (args.size() < 2) + return print_help(args[0]); int argnum = 1; - const char *command = argv[argnum++]; - bool help = (strcmp(command, COMMAND_HELP) == 0); + std::string command = args[argnum++]; + bool help(command == COMMAND_HELP); if (help) { - if (argc <= 2) - return print_help(argv[0]); - command = argv[argnum++]; + if (args.size() <= 2) + return print_help(args[0]); + command = args[argnum++]; } // iterate over commands to find our match for (auto & s_command : s_commands) - if (strcmp(command, s_command.name) == 0) + { + if (command == s_command.name) { const command_description &desc = s_command; // print help if that was requested if (help) - return print_help(argv[0], desc); + return print_help(args[0], desc); // otherwise, verify the parameters - parameters_t parameters; - while (argnum < argc) + parameters_map parameters; + while (argnum < args.size()) { // should be an option name - const char *arg = argv[argnum++]; - if (arg[0] != '-') - return print_help(argv[0], desc, "Expected option, not parameter"); + const std::string &arg = args[argnum++]; + if (arg.empty() || (arg[0] != '-')) + return print_help(args[0], desc, "Expected option, not parameter"); // iterate over valid options int valid; - for (valid = 0; valid < ARRAY_LENGTH(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++; // find the matching option description int optnum; - for (optnum = 0; optnum < ARRAY_LENGTH(s_options); optnum++) + for (optnum = 0; optnum < std::size(s_options); optnum++) if (strcmp(s_options[optnum].name, validname) == 0) break; - assert(optnum != ARRAY_LENGTH(s_options)); + assert(optnum != std::size(s_options)); // do we match? const option_description &odesc = s_options[optnum]; @@ -2989,31 +3462,31 @@ int CLIB_DECL main(int argc, char *argv[]) const char *param = ""; if (odesc.parameter) { - if (argnum >= argc || argv[argnum][0] == '-') - return print_help(argv[0], desc, "Option is missing parameter"); - param = argv[argnum++]; + if (argnum >= args.size() || (!args[argnum].empty() && args[argnum][0] == '-')) + return print_help(args[0], desc, "Option is missing parameter"); + param = args[argnum++].c_str(); } // add to the map if (!parameters.insert(std::make_pair(odesc.name, new std::string(param))).second) - return print_help(argv[0], desc, "Multiple parameters of the same type specified"); + return print_help(args[0], desc, "Multiple parameters of the same type specified"); break; } } // if not valid, error - if (valid == ARRAY_LENGTH(desc.valid_options)) - return print_help(argv[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 - for (int valid = 0; valid < ARRAY_LENGTH(desc.valid_options); valid++) + for (int valid = 0; valid < std::size(desc.valid_options); valid++) { const char *validname = desc.valid_options[valid]; if (validname == nullptr) break; if (*validname == REQUIRED[0] && parameters.find(++validname) == parameters.end()) - return print_help(argv[0], desc, "Required parameters missing"); + return print_help(args[0], desc, "Required parameters missing"); } // all clear, run the command @@ -3022,23 +3495,24 @@ int CLIB_DECL main(int argc, char *argv[]) (*s_command.handler)(parameters); return 0; } - catch (chd_error &err) + catch (std::error_condition const &err) { - fprintf(stderr, "CHD error occurred (main): %s\n", chd_file::error_string(err)); + 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(argv[0]); + return print_help(args[0]); } diff --git a/src/tools/floptool.cpp b/src/tools/floptool.cpp index 1953e7b0538..9ac9c3231ae 100644 --- a/src/tools/floptool.cpp +++ b/src/tools/floptool.cpp @@ -1,305 +1,728 @@ // license:BSD-3-Clause -// copyright-holders:Miodrag Milanovic +// copyright-holders:Olivier Galibert /*************************************************************************** - main.c - - Floptool command line front end - - 20/07/2011 Initial version by Miodrag Milanovic + (Floppy) image command-line manager ***************************************************************************/ -#include <stdio.h> -#include <string.h> -#include <ctype.h> -#include <stdlib.h> -#include <time.h> -#include <stdarg.h> -#include <assert.h> +#include "image_handler.h" + +#include "formats/fsblk.h" #include "corestr.h" +#include "ioprocs.h" +#include "path.h" +#include "strformat.h" -#include "formats/mfi_dsk.h" -#include "formats/dfi_dsk.h" -#include "formats/ipf_dsk.h" +#include "osdcomm.h" -#include "formats/hxcmfm_dsk.h" -#include "formats/ami_dsk.h" +#include <cassert> +#include <cctype> +#include <cstdarg> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <ctime> +#include <exception> -#include "formats/st_dsk.h" -#include "formats/pasti_dsk.h" -#include "formats/dsk_dsk.h" +static formats_table formats; -#include "formats/d88_dsk.h" -#include "formats/imd_dsk.h" -#include "formats/td0_dsk.h" -#include "formats/cqm_dsk.h" -#include "formats/pc_dsk.h" -#include "formats/naslite_dsk.h" +static void display_usage(const char *first_argument) +{ + std::string exe_name(core_filename_extract_base(first_argument)); -#include "formats/ap_dsk35.h" -#include "formats/ap2_dsk.h" + fprintf(stderr, "Usage: \n"); + fprintf(stderr, " %s identify <inputfile> [<inputfile> ...] -- Identify an image format\n", exe_name.c_str()); + fprintf(stderr, " %s flopconvert [input_format|auto] output_format <inputfile> <outputfile> -- Convert a floppy image\n", exe_name.c_str()); + fprintf(stderr, " %s flopcreate output_format filesystem <outputfile> -- Create a preformatted floppy image\n", exe_name.c_str()); + fprintf(stderr, " %s flopdir input_format filesystem <image> -- List the contents of a floppy image\n", exe_name.c_str()); + fprintf(stderr, " %s flopread input_format filesystem <image> <path> <outputfile> -- Extract a file from a floppy image\n", exe_name.c_str()); + fprintf(stderr, " %s flopwrite input_format filesystem <image> <inputfile> <path> -- Write a file into a floppy image\n", exe_name.c_str()); + fprintf(stderr, " %s hddir filesystem <image> -- List the contents of a hard disk image\n", exe_name.c_str()); + fprintf(stderr, " %s hdread filesystem <image> <path> <outputfile> -- Extract a file from a hard disk image\n", exe_name.c_str()); + fprintf(stderr, " %s hdwrite filesystem <image> <inputfile> <path> -- Write a file into a hard disk image\n", exe_name.c_str()); + fprintf(stderr, " %s version -- Display the current version of floptool\n", exe_name.c_str()); +} -#include "formats/atom_dsk.h" -#include "formats/acorn_dsk.h" +static void display_formats() +{ + int sk = 0; + for(const auto &e : formats.floppy_format_info_by_key) { + int sz = e.first.size(); + if(sz > sk) + sk = sz; + } -#include "formats/oric_dsk.h" + for(const auto &e : formats.filesystem_format_by_key) { + int sz = e.first.size(); + if(sz > sk) + sk = sz; + } -#include "formats/applix_dsk.h" + for(const auto &e : formats.floppy_create_info_by_key) { + int sz = e.first.size(); + if(sz > sk) + sk = sz; + } -#include "formats/hpi_dsk.h" + fprintf(stderr, "Supported floppy formats:\n\n"); + for(const auto &e : formats.floppy_format_info_by_category) + if(!e.second.empty()) { + fprintf(stderr, "%s:\n", e.first.c_str()); + for(auto *fif : e.second) + fprintf(stderr, " %-*s r%c - %s [%s]\n", sk, fif->m_format->name(), fif->m_format->supports_save() ? 'w' : '-', fif->m_format->description(), fif->m_format->extensions()); + } -#include "formats/dvk_mx_dsk.h" -#include "formats/aim_dsk.h" -#include "formats/m20_dsk.h" + fprintf(stderr, "\n\n"); + fprintf(stderr, "Supported filesystems (with floppy formatting names):\n\n"); + for(const auto &e : formats.filesystem_format_by_category) + if(!e.second.empty()) { + fprintf(stderr, "%s:\n", e.first.c_str()); + for(const auto &f : e.second) { + fprintf(stderr, " %-*s %c%c%c %c%c%c - %s\n", + sk, + f->m_manager->name(), + f->m_floppy || f->m_floppy_raw ? 'F' : '-', + f->m_hd ? 'H' : '-', + f->m_cd ? 'C' : '-', + f->m_manager->can_format() || f->m_floppy_raw ? 'f' : '-', + f->m_manager->can_read() ? 'r' : '-', + f->m_manager->can_write() ? 'w' : '-', + f->m_manager->description()); + for(auto &f2 : f->m_floppy_create) + fprintf(stderr, " %-*s - %s\n", + sk, + f2->m_name, + f2->m_description); + } + } +} -#include "formats/flex_dsk.h" -#include "formats/uniflex_dsk.h" +static void display_full_usage(char *argv[]) +{ + /* Usage */ + fprintf(stderr, "floptool - Generic floppy image manipulation tool for use with MAME\n\n"); + display_usage(argv[0]); + fprintf(stderr, "\n"); + display_formats(); +} +static int identify(int argc, char *argv[]) +{ + // Need to detect CHDs too -static floppy_format_type floppy_formats[] = { - FLOPPY_MFI_FORMAT, - FLOPPY_DFI_FORMAT, - FLOPPY_IPF_FORMAT, + if(argc<3) { + fprintf(stderr, "Missing name of file to identify.\n\n"); + display_usage(argv[0]); + return 1; + } - FLOPPY_MFM_FORMAT, - FLOPPY_ADF_FORMAT, + int sz = 0; + for(int i=2; i<argc; i++) { + int len = strlen(argv[i]); + if(len > sz) + sz = len; + } - FLOPPY_ST_FORMAT, - FLOPPY_MSA_FORMAT, - FLOPPY_PASTI_FORMAT, + for(int i=2; i<argc; i++) { + image_handler ih; + ih.set_on_disk_path(argv[i]); + auto scores = ih.identify(formats); + if(scores.empty()) + printf("%-*s : Unknown format\n", sz, argv[i]); + int sz2 = 0; + for(const auto &e : scores) { + int len = strlen(e.second->m_format->name()); + if(len > sz2) + sz2 = len; + } - FLOPPY_DSK_FORMAT, + bool first = true; + for(const auto &e : scores) { + printf("%-*s %c %c%c%c%c%c - %-*s %s\n", sz, first ? argv[i] : "", first ? ':' : ' ', + e.first & 0x10 ? '+' : '.', + e.first & 0x08 ? '+' : '.', + e.first & 0x04 ? '+' : '.', + e.first & 0x02 ? '+' : '.', + e.first & 0x01 ? '+' : '.', + sz2, e.second->m_format->name(), e.second->m_format->description()); + first = false; + } + } + return 0; +} + +static const floppy_format_info *find_floppy_source_format(const char *name, image_handler &ih) +{ + const floppy_format_info *source_format; + if(!core_stricmp(name, "auto")) { + auto scores = ih.identify(formats); + if(scores.empty()) { + fprintf(stderr, "Error: Could not identify the format of file %s\n", ih.get_on_disk_path().c_str()); + return nullptr; + } + if(scores.size() >= 2 && scores[0].first == scores[1].first) { + fprintf(stderr, "Ambiguous source format. Possible formats:\n"); + int sz = 0; + for(const auto &e : scores) { + int len = strlen(e.second->m_format->name()); + if(len > sz) + sz = len; + } + + for(const auto &e : scores) + printf(" %3d - %-*s %s\n", e.first, sz, e.second->m_format->name(), e.second->m_format->description()); + return nullptr; + } + source_format = scores[0].second; - FLOPPY_D88_FORMAT, - FLOPPY_IMD_FORMAT, - FLOPPY_TD0_FORMAT, - FLOPPY_CQM_FORMAT, - FLOPPY_PC_FORMAT, - FLOPPY_NASLITE_FORMAT, + } else { + source_format = formats.find_floppy_format_info_by_key(name); + if(!source_format) { + fprintf(stderr, "Error: Format '%s' unknown\n", name); + return nullptr; - FLOPPY_DC42_FORMAT, - FLOPPY_A216S_FORMAT, - FLOPPY_RWTS18_FORMAT, - FLOPPY_EDD_FORMAT, - FLOPPY_WOZ_FORMAT, + } + } + return source_format; +} - FLOPPY_ATOM_FORMAT, - FLOPPY_ACORN_SSD_FORMAT, - FLOPPY_ACORN_DSD_FORMAT, - FLOPPY_ACORN_DOS_FORMAT, - FLOPPY_ACORN_ADFS_OLD_FORMAT, - FLOPPY_ACORN_ADFS_NEW_FORMAT, +static int flopconvert(int argc, char *argv[]) +{ + if(argc!=6) { + fprintf(stderr, "Incorrect number of arguments.\n\n"); + display_usage(argv[0]); + return 1; + } - FLOPPY_ORIC_DSK_FORMAT, + image_handler ih; + ih.set_on_disk_path(argv[4]); - FLOPPY_APPLIX_FORMAT, + const floppy_format_info *source_format = find_floppy_source_format(argv[2], ih); + if(!source_format) + return 1; - FLOPPY_HPI_FORMAT, + const floppy_format_info *dest_format = formats.find_floppy_format_info_by_key(argv[3]); + if(!dest_format) { + fprintf(stderr, "Error: Format '%s' unknown\n", argv[3]); + return 1; + } + if(!dest_format->m_format->supports_save()) { + fprintf(stderr, "Error: Saving to format '%s' unsupported\n", argv[3]); + return 1; + } - FLOPPY_DVK_MX_FORMAT, - FLOPPY_AIM_FORMAT, - FLOPPY_M20_FORMAT, + if(ih.floppy_load(*source_format)) { + fprintf(stderr, "Error: Loading as format '%s' failed\n", source_format->m_format->name()); + return 1; + } - FLOPPY_FLEX_FORMAT, - FLOPPY_UNIFLEX_FORMAT -}; + ih.set_on_disk_path(argv[5]); -void CLIB_DECL ATTR_PRINTF(1,2) logerror(const char *format, ...) -{ - va_list arg; - va_start(arg, format); - vprintf(format, arg); - va_end(arg); + if(ih.floppy_save(*dest_format)) { + fprintf(stderr, "Error: Saving as format '%s' failed\n", dest_format->m_format->name()); + return 1; + } + + return 0; } -enum { FORMAT_COUNT = ARRAY_LENGTH(floppy_formats) }; +static fs::meta_data extract_meta_data(int &argc, char *argv[]) +{ + fs::meta_data result; -static floppy_image_format_t *formats[FORMAT_COUNT]; + int new_argc = 0; + for (int i = 0; i < argc; i++) + { + std::optional<fs::meta_name> attrname; + if (argv[i][0] == '-' && i < argc - 1) + attrname = fs::meta_data::from_entry_name(&argv[i][1]); + + if (attrname) + { + // we found a metadata variable; set it + result.set(*attrname, argv[i + 1]); + i++; + } + else + { + // we didn't; update argv + argv[new_argc++] = argv[i]; + } + } + + // we're done; update the argument count + argc = new_argc; + return result; +} -static void init_formats() +static int flopcreate(int argc, char *argv[]) { - for(int i=0; i != FORMAT_COUNT; i++) - formats[i] = floppy_formats[i](); + fs::meta_data meta = extract_meta_data(argc, argv); + + if(argc!=5) { + fprintf(stderr, "Incorrect number of arguments.\n\n"); + display_usage(argv[0]); + return 1; + } + + auto dest_format = formats.find_floppy_format_info_by_key(argv[2]); + if(!dest_format) { + fprintf(stderr, "Error: Floppy format '%s' unknown\n", argv[2]); + return 1; + } + if(!dest_format->m_format->supports_save()) { + fprintf(stderr, "Error: Saving to format '%s' unsupported\n", argv[2]); + return 1; + } + + auto create_fs = formats.find_floppy_create_info_by_key(argv[3]); + if(!create_fs) { + fprintf(stderr, "Error: Floppy creation format '%s' unknown\n", argv[3]); + return 1; + } + if(create_fs->m_manager && !create_fs->m_manager->can_format()) { + fprintf(stderr, "Error: Floppy creation format '%s' does not support creating new images\n", argv[3]); + return 1; + } + + image_handler ih; + ih.set_on_disk_path(argv[4]); + + ih.floppy_create(*create_fs, meta); + return ih.floppy_save(*dest_format); } -static floppy_image_format_t *find_format_by_name(const char *name) +static void dir_scan(fs::filesystem_t *fs, u32 depth, const std::vector<std::string> &path, std::vector<std::vector<std::string>> &entries, const std::unordered_map<fs::meta_name, size_t> &nmap, size_t nc, const std::vector<fs::meta_description> &dmetad, const std::vector<fs::meta_description> &fmetad) { - for(int i=0; i != FORMAT_COUNT; i++) - if(!core_stricmp(name, formats[i]->name())) - return formats[i]; - return nullptr; + std::string head; + for(u32 i = 0; i != depth; i++) + head += " "; + auto [err, contents] = fs->directory_contents(path); + if(err) + return; // FIXME: don't swallow errors + for(const auto &c : contents) { + size_t id = entries.size(); + entries.resize(id+1); + entries[id].resize(nc); + switch(c.m_type) { + case fs::dir_entry_type::dir: { + for(const auto &m : dmetad) { + if(!c.m_meta.has(m.m_name)) + continue; + size_t slot = nmap.find(m.m_name)->second; + std::string val = c.m_meta.get(m.m_name).as_string(); + if(slot == 0) + val = head + "dir " + val; + entries[id][slot] = val; + } + auto npath = path; + npath.push_back(c.m_name); + dir_scan(fs, depth+1, npath, entries, nmap, nc, dmetad, fmetad); + break; + } + case fs::dir_entry_type::file: { + for(const auto &m : fmetad) { + if(!c.m_meta.has(m.m_name)) + continue; + size_t slot = nmap.find(m.m_name)->second; + std::string val = c.m_meta.get(m.m_name).as_string(); + if(slot == 0) + val = head + "file " + val; + entries[id][slot] = val; + } + break; + } + } + } } -static floppy_image_format_t *find_format_by_identify(io_generic *image) +static int generic_dir(image_handler &ih) { - int best = 0; - floppy_image_format_t *best_fif = nullptr; - - for(int i = 0; i != FORMAT_COUNT; i++) { - floppy_image_format_t *fif = formats[i]; - int score = fif->identify(image, floppy_image::FF_UNKNOWN); - if(score > best) { - best = score; - best_fif = fif; + auto [fsm, fs] = ih.get_fs(); + auto vmetad = fsm->volume_meta_description(); + auto fmetad = fsm->file_meta_description(); + auto dmetad = fsm->directory_meta_description(); + + auto vmeta = fs->volume_metadata(); + if(!vmeta.empty()) { + std::string vinf = "Volume:"; + for(const auto &e : vmetad) + vinf += util::string_format(" %s=%s", fs::meta_data::entry_name(e.m_name), vmeta.get(e.m_name).as_string()); + printf("%s\n\n", vinf.c_str()); + } + + std::vector<fs::meta_name> names; + names.push_back(fs::meta_name::name); + for(const auto &e : fmetad) + if(e.m_name != fs::meta_name::name) + names.push_back(e.m_name); + for(const auto &e : dmetad) + if(std::find(names.begin(), names.end(), e.m_name) == names.end()) + names.push_back(e.m_name); + + std::unordered_map<fs::meta_name, size_t> nmap; + for(size_t i = 0; i != names.size(); i++) + nmap[names[i]] = i; + + std::vector<std::vector<std::string>> entries; + + entries.resize(1); + for(fs::meta_name n : names) + entries[0].push_back(fs::meta_data::entry_name(n)); + + dir_scan(fs, 0, std::vector<std::string>(), entries, nmap, names.size(), dmetad, fmetad); + + std::vector<u32> sizes(names.size()); + + for(const auto &e : entries) + for(unsigned int i=0; i != names.size(); i++) + sizes[i] = std::max<u32>(sizes[i], e[i].size()); + + for(const auto &e : entries) { + std::string l; + for(unsigned int i=0; i != names.size(); i++) { + if(i) + l += ' '; + l += util::string_format("%-*s", sizes[i], e[i]); } + printf("%s\n", l.c_str()); } - return best_fif; + + return 0; } -static void display_usage() +static int flopdir(int argc, char *argv[]) { - fprintf(stderr, "Usage: \n"); - fprintf(stderr, " floptool.exe identify <inputfile> [<inputfile> ...]\n"); - fprintf(stderr, " floptool.exe convert [input_format|auto] output_format <inputfile> <outputfile>\n"); + if(argc!=5) { + fprintf(stderr, "Incorrect number of arguments.\n\n"); + display_usage(argv[0]); + return 1; + } + + image_handler ih; + ih.set_on_disk_path(argv[4]); + + const floppy_format_info *source_format = find_floppy_source_format(argv[2], ih); + if(!source_format) + return 1; + + auto fs = formats.find_filesystem_format_by_key(argv[3]); + if(!fs) { + fprintf(stderr, "Error: Filesystem '%s' unknown\n", argv[3]); + return 1; + } + + if(!fs->m_manager || !fs->m_manager->can_read()) { + fprintf(stderr, "Error: Filesystem '%s' does not implement reading\n", argv[3]); + return 1; + } + + if(ih.floppy_load(*source_format)) { + fprintf(stderr, "Error: Loading as format '%s' failed\n", source_format->m_format->name()); + return 1; + } + + if(ih.floppy_mount_fs(*fs)) { + fprintf(stderr, "Error: Parsing as filesystem '%s' failed\n", fs->m_manager->name()); + return 1; + } + + return generic_dir(ih); } -static void display_formats() +static int hddir(int argc, char *argv[]) { - fprintf(stderr, "Supported formats:\n\n"); - for(int i = 0; i != FORMAT_COUNT; i++) - { - floppy_image_format_t *fif = formats[i]; - fprintf(stderr, "%15s - %s [%s]\n", fif->name(), fif->description(), fif->extensions()); + if(argc!=4) { + fprintf(stderr, "Incorrect number of arguments.\n\n"); + display_usage(argv[0]); + return 1; } + + image_handler ih; + ih.set_on_disk_path(argv[3]); + + auto fs = formats.find_filesystem_format_by_key(argv[2]); + if(!fs) { + fprintf(stderr, "Error: Filesystem '%s' unknown\n", argv[2]); + return 1; + } + + if(!fs->m_manager || !fs->m_manager->can_read()) { + fprintf(stderr, "Error: Filesystem '%s' does not implement reading\n", argv[2]); + return 1; + } + + if(ih.hd_mount_fs(*fs)) { + fprintf(stderr, "Error: Parsing as filesystem '%s' failed\n", fs->m_manager->name()); + return 1; + } + + return generic_dir(ih); } -static void display_full_usage() + +static int generic_read(image_handler &ih, const char *srcpath, const char *dstpath) { - /* Usage */ - fprintf(stderr, "floptool - Generic floppy image manipulation tool for use with MAME\n\n"); - display_usage(); - fprintf(stderr, "\n"); - display_formats(); - fprintf(stderr, "\nExample usage:\n"); - fprintf(stderr, " floptool.exe identify image.dsk\n\n"); + auto [fsm, fs] = ih.get_fs(); + std::ignore = fsm; + + std::vector<std::string> path = ih.path_split(srcpath); + auto [err, dfork] = fs->file_read(path); + if(err) { + fprintf(stderr, "File reading failed: %s\n", err.message().c_str()); + return 1; + } + image_handler::fsave(dstpath, dfork); + + auto [err2, rfork] = fs->file_rsrc_read(path); + if(!err2 && !rfork.empty()) + image_handler::fsave_rsrc(image_handler::path_make_rsrc(dstpath), rfork); + + return 0; } -static int identify(int argc, char *argv[]) + +static int flopread(int argc, char *argv[]) { - if (argc<3) { - fprintf(stderr, "Missing name of file to identify.\n\n"); - display_usage(); + if(argc!=7) { + fprintf(stderr, "Incorrect number of arguments.\n\n"); + display_usage(argv[0]); return 1; } - for(int i=2; i<argc; i++) { - char msg[4096]; - sprintf(msg, "Error opening %s for reading", argv[i]); - FILE *f = fopen(argv[i], "rb"); - if (!f) { - perror(msg); - return 1; - } - io_generic io; - io.file = f; - io.procs = &stdio_ioprocs_noclose; - io.filler = 0xff; - - floppy_image_format_t *best_fif = find_format_by_identify(&io); - if (best_fif) - printf("%s : %s\n", argv[i], best_fif->description()); - else - printf("%s : Unknown format\n", argv[i]); - fclose(f); + image_handler ih; + ih.set_on_disk_path(argv[4]); + + const floppy_format_info *source_format = find_floppy_source_format(argv[2], ih); + if(!source_format) + return 1; + + auto fs = formats.find_filesystem_format_by_key(argv[3]); + if(!fs) { + fprintf(stderr, "Error: Filesystem '%s' unknown\n", argv[3]); + return 1; } - return 0; + + if(!fs->m_manager || !fs->m_manager->can_read()) { + fprintf(stderr, "Error: Filesystem '%s' does not implement reading\n", argv[3]); + return 1; + } + + if(ih.floppy_load(*source_format)) { + fprintf(stderr, "Error: Loading as format '%s' failed\n", source_format->m_format->name()); + return 1; + } + + if(ih.floppy_mount_fs(*fs)) { + fprintf(stderr, "Error: Parsing as filesystem '%s' failed\n", fs->m_manager->name()); + return 1; + } + + return generic_read(ih, argv[5], argv[6]); } -static int convert(int argc, char *argv[]) +static int hdread(int argc, char *argv[]) { - if (argc!=6) { + if(argc!=6) { fprintf(stderr, "Incorrect number of arguments.\n\n"); - display_usage(); + display_usage(argv[0]); return 1; } - floppy_image_format_t *source_format, *dest_format; + image_handler ih; + ih.set_on_disk_path(argv[3]); - char msg[4096]; - sprintf(msg, "Error opening %s for reading", argv[4]); - FILE *f = fopen(argv[4], "rb"); - if (!f) { - perror(msg); + auto fs = formats.find_filesystem_format_by_key(argv[2]); + if(!fs) { + fprintf(stderr, "Error: Filesystem '%s' unknown\n", argv[2]); return 1; } - io_generic source_io; - source_io.file = f; - source_io.procs = &stdio_ioprocs_noclose; - source_io.filler = 0xff; - if(!core_stricmp(argv[2], "auto")) { - source_format = find_format_by_identify(&source_io); - if(!source_format) { - fprintf(stderr, "Error: Could not identify the format of file %s\n", argv[4]); + if(!fs->m_manager || !fs->m_manager->can_read()) { + fprintf(stderr, "Error: Filesystem '%s' does not implement reading\n", argv[2]); + return 1; + } + + if(ih.hd_mount_fs(*fs)) { + fprintf(stderr, "Error: Parsing as filesystem '%s' failed\n", fs->m_manager->name()); + return 1; + } + + return generic_read(ih, argv[4], argv[5]); +} + + + +static int generic_write(image_handler &ih, const char *srcpath, const char *dstpath) +{ + auto [fsm, fs] = ih.get_fs(); + + std::vector<std::string> path = ih.path_split(dstpath); + auto [err, meta] = fs->metadata(path); + std::ignore = meta; + + 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 failed: %s\n", err.message().c_str()); return 1; } + } - } else { - source_format = find_format_by_name(argv[2]); - if(!source_format) { - fprintf(stderr, "Error: Format '%s' unknown\n", argv[2]); - return 1; + auto dfork = image_handler::fload(srcpath); + err = fs->file_write(path, dfork); + if(err) { + fprintf(stderr, "File writing failed: %s\n", err.message().c_str()); + return 1; + } + + if(fsm->has_rsrc()) { + std::string rpath = image_handler::path_make_rsrc(dstpath); + + if(image_handler::fexists(rpath)) { + auto rfork = image_handler::fload_rsrc(rpath); + if(!rfork.empty()) { + err = fs->file_rsrc_write(path, rfork); + fprintf(stderr, "File resource fork writing failed: %s\n", err.message().c_str()); + return 1; + } } } - dest_format = find_format_by_name(argv[3]); - if(!dest_format) { - fprintf(stderr, "Error: Format '%s' unknown\n", argv[3]); + return 0; +} + + +static int flopwrite(int argc, char *argv[]) +{ + if(argc!=7) { + fprintf(stderr, "Incorrect number of arguments.\n\n"); + display_usage(argv[0]); + return 1; + } + + image_handler ih; + ih.set_on_disk_path(argv[4]); + + const floppy_format_info *source_format = find_floppy_source_format(argv[2], ih); + if(!source_format) + return 1; + + auto fs = formats.find_filesystem_format_by_key(argv[3]); + if(!fs) { + fprintf(stderr, "Error: Filesystem '%s' unknown\n", argv[3]); + return 1; + } + + if(!fs->m_manager || !fs->m_manager->can_read()) { + fprintf(stderr, "Error: Filesystem '%s' does not implement reading\n", argv[3]); return 1; } - if(!dest_format->supports_save()) { - fprintf(stderr, "Error: saving to format '%s' unsupported\n", argv[3]); + + if(ih.floppy_load(*source_format)) { + fprintf(stderr, "Error: Loading as format '%s' failed\n", source_format->m_format->name()); + return 1; + } + + if(ih.floppy_mount_fs(*fs)) { + fprintf(stderr, "Error: Parsing as filesystem '%s' failed\n", fs->m_manager->name()); + return 1; + } + + int err = generic_write(ih, argv[5], argv[6]); + if(err) + return err; + + ih.fs_to_floppy(); + if(ih.floppy_save(*source_format)) + return 1; + + return 0; +} + +static int hdwrite(int argc, char *argv[]) +{ + if(argc!=6) { + fprintf(stderr, "Incorrect number of arguments.\n\n"); + display_usage(argv[0]); return 1; } - sprintf(msg, "Error opening %s for writing", argv[5]); - f = fopen(argv[5], "wb"); - if (!f) { - perror(msg); + + image_handler ih; + ih.set_on_disk_path(argv[3]); + + auto fs = formats.find_filesystem_format_by_key(argv[2]); + if(!fs) { + fprintf(stderr, "Error: Filesystem '%s' unknown\n", argv[2]); return 1; } - io_generic dest_io; - dest_io.file = f; - dest_io.procs = &stdio_ioprocs_noclose; - dest_io.filler = 0xff; - floppy_image image(84, 2, floppy_image::FF_UNKNOWN); - if(!source_format->load(&source_io, floppy_image::FF_UNKNOWN, &image)) { - fprintf(stderr, "Error: parsing input file as '%s' failed\n", source_format->name()); + if(!fs->m_manager || !fs->m_manager->can_read()) { + fprintf(stderr, "Error: Filesystem '%s' does not implement reading\n", argv[2]); return 1; } - if(!dest_format->save(&dest_io, &image)) { - fprintf(stderr, "Error: writing output file as '%s' failed\n", dest_format->name()); + if(ih.hd_mount_fs(*fs)) { + fprintf(stderr, "Error: Parsing as filesystem '%s' failed\n", fs->m_manager->name()); return 1; } - fclose((FILE *)source_io.file); - fclose((FILE *)dest_io.file); + return generic_write(ih, argv[4], argv[5]); +} +static int version(int argc, char *argv[]) +{ + extern const char build_version[]; + fprintf(stdout, "%s\n", build_version); return 0; } int CLIB_DECL main(int argc, char *argv[]) { - init_formats(); + formats.init(); - if (argc == 1) { - display_full_usage(); + if(argc == 1) { + display_full_usage(argv); return 0; } - if (!core_stricmp("identify", argv[1])) - return identify(argc, argv); - else if (!core_stricmp("convert", argv[1])) - return convert(argc, argv); - else { - fprintf(stderr, "Unknown command '%s'\n\n", argv[1]); - display_usage(); + try { + if(!core_stricmp("identify", argv[1])) + return identify(argc, argv); + else if(!core_stricmp("flopconvert", argv[1])) + return flopconvert(argc, argv); + else if(!core_stricmp("flopcreate", argv[1])) + return flopcreate(argc, argv); + else if(!core_stricmp("flopdir", argv[1])) + return flopdir(argc, argv); + else if(!core_stricmp("flopread", argv[1])) + return flopread(argc, argv); + else if(!core_stricmp("flopwrite", argv[1])) + return flopwrite(argc, argv); + else if(!core_stricmp("hddir", argv[1])) + return hddir(argc, argv); + else if(!core_stricmp("hdread", argv[1])) + return hdread(argc, argv); + else if(!core_stricmp("hdwrite", argv[1])) + return hdwrite(argc, argv); + else if (!core_stricmp("version", argv[1])) + return version(argc, argv); + else { + fprintf(stderr, "Unknown command '%s'\n\n", argv[1]); + display_usage(argv[0]); + return 1; + } + } catch(const std::exception &err) { + fprintf(stderr, "Error: %s\n", err.what()); return 1; } } diff --git a/src/tools/image_handler.cpp b/src/tools/image_handler.cpp new file mode 100644 index 00000000000..14976516e1c --- /dev/null +++ b/src/tools/image_handler.cpp @@ -0,0 +1,397 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +// Image generic handler class and helpers + +#include "image_handler.h" + +#include "formats/all.h" +#include "formats/fsblk_vec.h" +#include "formats/fs_unformatted.h" + +#include "ioprocs.h" +#include "ioprocsfill.h" +#include "ioprocsvec.h" +#include "multibyte.h" +#include "strformat.h" + +#include <algorithm> + + +// Format enumeration + +namespace { + struct enumerator : public mame_formats_enumerator { + formats_table *m_table; + std::string m_category; + + enumerator(formats_table *table) : mame_formats_enumerator(), m_table(table), m_category("None") {} + + virtual ~enumerator() = default; + virtual void add(const cassette_image::Format *const *formats) {} + + virtual void category(const char *name) { + m_category = name; + } + + virtual void add(const floppy_image_format_t &format) { + m_table->floppy_format_infos.emplace_back(std::make_unique<floppy_format_info>(&format, m_category)); + } + + virtual void add(const fs::manager_t &fs) { + m_table->filesystem_formats.emplace_back(std::make_unique<filesystem_format>(&fs, m_category)); + } + }; + + struct fs_enum : public fs::manager_t::floppy_enumerator { + filesystem_format *m_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; + m_format->m_floppy_create.emplace_back(std::make_unique<floppy_create_info>(m_format->m_manager, &type, image_size, name, description)); + } + + virtual void add_raw(const char *name, u32 key, const char *description) override { + m_format->m_floppy_raw = true; + m_format->m_floppy_create.emplace_back(std::make_unique<floppy_create_info>(name, key, description)); + } + }; +} + +void formats_table::init() +{ + std::vector<uint32_t> variants; + + enumerator en(this); + mame_formats_full_list(en); + + for(auto &f : filesystem_formats) { + fs_enum fen(f.get(), floppy_image::FF_UNKNOWN, variants); + f->m_manager->enumerate_f(fen); + } + + for(auto &f : floppy_format_infos) { + auto *ff = f.get(); + std::string key = ff->m_format->name(); + auto i = floppy_format_info_by_key.find(key); + if(i != floppy_format_info_by_key.end()) { + fprintf(stderr, "Collision on floppy format name %s between \"%s\" and \"%s\".\n", + ff->m_format->name(), + ff->m_format->description(), + i->second->m_format->description()); + exit(1); + } + + floppy_format_info_by_key[key] = ff; + floppy_format_info_by_category[ff->m_category].push_back(ff); + } + + for(auto &f : filesystem_formats) { + auto *ff = f.get(); + std::string key = ff->m_manager->name(); + auto i = filesystem_format_by_key.find(key); + if(i != filesystem_format_by_key.end()) { + fprintf(stderr, "Collision on filesystem name %s between \"%s\" and \"%s\".\n", + ff->m_manager->name(), + ff->m_manager->description(), + i->second->m_manager->description()); + exit(1); + } + + filesystem_format_by_key[key] = ff; + filesystem_format_by_category[ff->m_category].push_back(ff); + + for(auto &f2 : ff->m_floppy_create) { + auto *ff2 = f2.get(); + key = ff2->m_name; + auto i = floppy_create_info_by_key.find(key); + if(i != floppy_create_info_by_key.end()) { + fprintf(stderr, "Collision on floppy create name %s between \"%s\" and \"%s\".\n", + ff2->m_name, + ff2->m_description, + i->second->m_description); + exit(1); + } + + floppy_create_info_by_key[key] = ff2; + } + } +} + +const floppy_format_info *formats_table::find_floppy_format_info_by_key(const std::string &key) const +{ + auto i = floppy_format_info_by_key.find(key); + return i == floppy_format_info_by_key.end() ? nullptr : i->second; +} + +const filesystem_format *formats_table::find_filesystem_format_by_key(const std::string &key) const +{ + auto i = filesystem_format_by_key.find(key); + return i == filesystem_format_by_key.end() ? nullptr : i->second; +} + +const floppy_create_info *formats_table::find_floppy_create_info_by_key(const std::string &key) const +{ + auto i = floppy_create_info_by_key.find(key); + return i == floppy_create_info_by_key.end() ? nullptr : i->second; +} + + +// Image handling + +std::vector<u8> image_handler::fload(std::string path) +{ + auto fi = fopen(path.c_str(), "rb"); + if(!fi) { + perror(util::string_format("Error opening %s for reading", path).c_str()); + exit(1); + } + fseek(fi, 0, SEEK_END); + long size = ftell(fi); + std::vector<u8> filedata(size); + fseek(fi, 0, SEEK_SET); + fread(filedata.data(), filedata.size(), 1, fi); + fclose(fi); + + return filedata; +} + +std::vector<u8> image_handler::fload_rsrc(std::string path) +{ + auto filedata = fload(path); + const u8 *head = filedata.data(); + + if(get_u32be(head+0x00) == 0x00051607 && + get_u32be(head+0x04) == 0x00020000) { + u16 nent = get_u16be(head+0x18); + for(u16 i=0; i != nent; i++) { + const u8 *e = head + 12*i; + if(get_u32be(e+0) == 2) { + u32 start = get_u32be(e+4); + u32 len = get_u32be(e+8); + filedata.erase(filedata.begin(), filedata.begin() + start); + filedata.erase(filedata.begin() + len, filedata.end()); + return filedata; + } + } + } + filedata.clear(); + return filedata; +} + +void image_handler::fsave(std::string path, const std::vector<u8> &data) +{ + auto fo = fopen(path.c_str(), "wb"); + if(!fo) { + perror(util::string_format("Error opening %s for writing", path).c_str()); + exit(1); + } + + fwrite(data.data(), data.size(), 1, fo); + fclose(fo); +} + +void image_handler::fsave_rsrc(std::string path, const std::vector<u8> &data) +{ + u8 head[0x2a]; + + put_u32be(head+0x00, 0x00051607); // Magic + put_u32be(head+0x04, 0x00020000); // Version + memset(head+0x08, 0, 16); // Filler + put_u16be(head+0x18, 1); // Number of entries + put_u32be(head+0x1a, 2); // Resource fork + put_u32be(head+0x22, 0x2a); // Offset in the file + put_u32be(head+0x26, data.size()); // Length + + auto fo = fopen(path.c_str(), "wb"); + if(!fo) { + perror(util::string_format("Error opening %s for writing", path).c_str()); + exit(1); + } + + fwrite(head, sizeof(head), 1, fo); + fwrite(data.data(), data.size(), 1, fo); + fclose(fo); +} + +image_handler::image_handler() : m_floppy_image(84, 2, floppy_image::FF_UNKNOWN) +{ +} + +void image_handler::set_on_disk_path(std::string path) +{ + m_on_disk_path = path; +} + +std::vector<std::pair<u8, const floppy_format_info *>> image_handler::identify(const formats_table &formats) +{ + std::vector<std::pair<u8, const floppy_format_info *>> res; + std::vector<uint32_t> variants; + + FILE *f = fopen(m_on_disk_path.c_str(), "rb"); + if (!f) { + std::string msg = util::string_format("Error opening %s for reading", m_on_disk_path); + perror(msg.c_str()); + return res; + } + + auto io = util::stdio_read(f, 0xff); + + for(const auto &e : formats.floppy_format_info_by_key) { + u8 score = e.second->m_format->identify(*io, floppy_image::FF_UNKNOWN, variants); + if(score && e.second->m_format->extension_matches(m_on_disk_path.c_str())) + score |= floppy_image_format_t::FIFID_EXT; + if(score) + 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; +} + +bool image_handler::floppy_load(const floppy_format_info &format) +{ + std::vector<uint32_t> variants; + FILE *f = fopen(m_on_disk_path.c_str(), "rb"); + if (!f) { + std::string msg = util::string_format("Error opening %s for reading", m_on_disk_path); + perror(msg.c_str()); + return true; + } + + auto io = util::stdio_read(f, 0xff); + + return !format.m_format->load(*io, floppy_image::FF_UNKNOWN, variants, m_floppy_image); +} + +bool image_handler::floppy_save(const floppy_format_info &format) const +{ + std::vector<uint32_t> variants; + FILE *f = fopen(m_on_disk_path.c_str(), "wb"); + if (!f) { + auto msg = util::string_format("Error opening %s for writing", m_on_disk_path); + perror(msg.c_str()); + return true; + } + + auto io = util::stdio_read_write(f, 0xff); + + return !format.m_format->save(*io, variants, m_floppy_image); +} + +void image_handler::floppy_create(const floppy_create_info &format, fs::meta_data meta) +{ + if(format.m_type) { + std::vector<uint32_t> variants; + std::vector<u8> img(format.m_image_size); + fs::fsblk_vec_t blockdev(img); + auto fs = format.m_manager->mount(blockdev); + fs->format(meta); + + auto io = util::ram_read(img.data(), img.size(), 0xff); + format.m_type->load(*io, floppy_image::FF_UNKNOWN, variants, m_floppy_image); + } else { + fs::unformatted_image::format(format.m_key, &m_floppy_image); + } +} + +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 : fmtcopy.m_floppy_create) { + if(ci->m_type != m_floppy_fs_converter) { + std::vector<uint32_t> variants; + m_floppy_fs_converter = ci->m_type; + m_sector_image.clear(); + util::random_read_write_fill_wrapper<util::vector_read_write_adapter<u8>, 0xff> io(m_sector_image); + m_floppy_fs_converter->save(io, variants, m_floppy_image); + } + + if(ci->m_image_size == m_sector_image.size()) + goto success; + } + m_floppy_fs_converter = nullptr; + m_sector_image.clear(); + return true; + + success: + m_fsblk.reset(new fs::fsblk_vec_t(m_sector_image)); + m_fsm = format.m_manager; + m_fs = m_fsm->mount(*m_fsblk); + return false; +} + +bool image_handler::hd_mount_fs(const filesystem_format &format) +{ + // Should use the chd mechanisms, one thing at a time... + + m_sector_image = fload(m_on_disk_path); + m_fsblk.reset(new fs::fsblk_vec_t(m_sector_image)); + m_fsm = format.m_manager; + m_fs = m_fsm->mount(*m_fsblk); + return false; +} + +void image_handler::fs_to_floppy() +{ + std::vector<uint32_t> variants; + auto io = util::ram_read(m_sector_image.data(), m_sector_image.size(), 0xff); + m_floppy_fs_converter->load(*io, floppy_image::FF_UNKNOWN, variants, m_floppy_image); +} + +std::vector<std::string> image_handler::path_split(std::string path) const +{ + std::string opath = path; + std::vector<std::string> rpath; + if(m_fsm->has_subdirectories()) { + std::string element; + char sep = m_fsm->directory_separator(); + for(char c : opath) { + if(c == sep) { + if(!element.empty()) { + rpath.push_back(element); + element.clear(); + } + } else + element += c; + } + if(!element.empty()) + rpath.push_back(element); + + } else + rpath.push_back(opath); + + return rpath; +} + +bool image_handler::fexists(std::string path) +{ + auto f = fopen(path.c_str(), "rb"); + if(f != nullptr) { + fclose(f); + return true; + } + return false; +} + + +std::string image_handler::path_make_rsrc(std::string path) +{ + auto p = path.end(); + while(p != path.begin() && p[-1] != '/') + p--; + std::string rpath(path.begin(), p); + rpath += "._"; + rpath += std::string(p, path.end()); + return rpath; +} + diff --git a/src/tools/image_handler.h b/src/tools/image_handler.h new file mode 100644 index 00000000000..3577f60dbf8 --- /dev/null +++ b/src/tools/image_handler.h @@ -0,0 +1,119 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +// Image generic handler class and helpers + +#ifndef MAME_TOOLS_IMAGE_HANDLER_H +#define MAME_TOOLS_IMAGE_HANDLER_H + +#pragma once + +#include "formats/flopimg.h" +#include "formats/fsmgr.h" +#include "harddisk.h" + +#include <cstdint> +#include <map> +#include <memory> +#include <string> +#include <vector> + + +using u8 = uint8_t; +using u16 = uint16_t; +using u32 = uint32_t; + +struct floppy_format_info { + const floppy_image_format_t *m_format; + std::string m_category; + + floppy_format_info(const floppy_image_format_t *format, std::string category) : m_format(format), m_category(category) {} +}; + +struct floppy_create_info { + const fs::manager_t *m_manager; + + const floppy_image_format_t *m_type; + u32 m_image_size; + u32 m_key; + const char *m_name; + const char *m_description; + + floppy_create_info(const fs::manager_t *manager, const floppy_image_format_t *type, u32 image_size, const char *name, const char *description) : + m_manager(manager), m_type(type), m_image_size(image_size), m_key(0), m_name(name), m_description(description) + { } + + floppy_create_info(const char *name, u32 key, const char *description) : + m_manager(nullptr), m_type(nullptr), m_image_size(0), m_key(key), m_name(name), m_description(description) + { } +}; + +struct filesystem_format { + const fs::manager_t *m_manager; + std::vector<std::unique_ptr<floppy_create_info>> m_floppy_create; + std::string m_category; + bool m_floppy, m_floppy_raw, m_hd, m_cd; + + filesystem_format(const fs::manager_t *manager, std::string category) : m_manager(manager), m_category(category), m_floppy(false), m_floppy_raw(false), m_hd(false), m_cd(false) {} +}; + +struct formats_table { + std::vector<std::unique_ptr<floppy_format_info>> floppy_format_infos; + std::vector<std::unique_ptr<filesystem_format>> filesystem_formats; + + std::map<std::string, const floppy_format_info *> floppy_format_info_by_key; + std::map<std::string, const filesystem_format *> filesystem_format_by_key; + std::map<std::string, const floppy_create_info *> floppy_create_info_by_key; + + std::map<std::string, std::vector<const floppy_format_info *>> floppy_format_info_by_category; + std::map<std::string, std::vector<const filesystem_format *>> filesystem_format_by_category; + + void init(); + + const floppy_format_info *find_floppy_format_info_by_key(const std::string &key) const; + const filesystem_format *find_filesystem_format_by_key(const std::string &key) const; + const floppy_create_info *find_floppy_create_info_by_key(const std::string &key) const; +}; + +class image_handler { +public: + image_handler(); + + void set_on_disk_path(std::string path); + const std::string &get_on_disk_path() const { return m_on_disk_path; } + + std::vector<std::pair<u8, const floppy_format_info *>> identify(const formats_table &formats); + + bool floppy_load(const floppy_format_info &format); + bool floppy_save(const floppy_format_info &format) const; + + void floppy_create(const floppy_create_info &format, fs::meta_data meta); + bool floppy_mount_fs(const filesystem_format &format); + bool hd_mount_fs(const filesystem_format &format); + void fs_to_floppy(); + + std::pair<const fs::manager_t *, fs::filesystem_t *> get_fs() const { return std::make_pair(m_fsm, m_fs.get()); } + + std::vector<std::string> path_split(std::string path) const; + + static std::vector<u8> fload(std::string path); + static std::vector<u8> fload_rsrc(std::string path); + static void fsave(std::string path, const std::vector<u8> &data); + static void fsave_rsrc(std::string path, const std::vector<u8> &data); + static bool fexists(std::string path); + static std::string path_make_rsrc(std::string path); + +private: + std::string m_on_disk_path; + + floppy_image m_floppy_image; + + const floppy_image_format_t *m_floppy_fs_converter = nullptr; + std::vector<u8> m_sector_image; + std::unique_ptr<fs::fsblk_t> m_fsblk; + const fs::manager_t *m_fsm = nullptr; + std::unique_ptr<fs::filesystem_t> m_fs; + +}; + +#endif // MAME_TOOLS_IMAGE_HANDLER_H diff --git a/src/tools/imgtool/charconv.cpp b/src/tools/imgtool/charconv.cpp index 0dadc8acb88..3ff6de62081 100644 --- a/src/tools/imgtool/charconv.cpp +++ b/src/tools/imgtool/charconv.cpp @@ -8,32 +8,13 @@ ***************************************************************************/ -#include "corestr.h" #include "charconv.h" -#include "unicode.h" -#include "coretmpl.h" - -imgtool::simple_charconverter imgtool::charconverter_iso_8859_1(nullptr, nullptr); - - -//------------------------------------------------- -// from_utf8 -//------------------------------------------------- - -void imgtool::charconverter::from_utf8(std::ostream &dest, const std::string &src) const -{ - from_utf8(dest, src.c_str(), src.size()); -} +#include "corestr.h" -//------------------------------------------------- -// to_utf8 -//------------------------------------------------- +#include <algorithm> -void imgtool::charconverter::to_utf8(std::ostream &dest, const std::string &src) const -{ - to_utf8(dest, src.c_str(), src.size()); -} +imgtool::simple_charconverter imgtool::charconverter_iso_8859_1(nullptr, nullptr); //------------------------------------------------- @@ -63,23 +44,23 @@ imgtool::simple_charconverter::simple_charconverter(const char32_t lowpage[0x80] // from_utf8 //------------------------------------------------- -void imgtool::simple_charconverter::from_utf8(std::ostream &dest, const char *src, size_t src_length) const +void imgtool::simple_charconverter::from_utf8(std::ostream &dest, std::string_view src) const { // normalize the incoming unicode - std::string normalized_src = normalize_unicode(src, src_length, m_norm); + std::string const normalized_src = normalize_unicode(src, m_norm); - auto iter = normalized_src.begin(); - while (iter != normalized_src.end()) + auto nsrc = std::string_view(normalized_src); + while (!nsrc.empty()) { // get the next character char32_t ch; - int rc = uchar_from_utf8(&ch, &*iter, normalized_src.end() - iter); + int rc = uchar_from_utf8(&ch, nsrc); if (rc < 0) { ch = 0xFFFD; rc = 1; } - iter += rc; + nsrc.remove_prefix(rc); // do the reverse lookup auto lookup = std::lower_bound(m_reverse_lookup.begin(), m_reverse_lookup.end(), ch, [](const std::pair<char32_t, char> &a, const char32_t &b) @@ -99,24 +80,24 @@ void imgtool::simple_charconverter::from_utf8(std::ostream &dest, const char *sr // to_utf8 //------------------------------------------------- -void imgtool::simple_charconverter::to_utf8(std::ostream &dest, const char *src, size_t src_length) const +void imgtool::simple_charconverter::to_utf8(std::ostream &dest, std::string_view src) const { - for (size_t i = 0; i < src_length; i++) + for (uint8_t c : src) { // which page is this in? - const char32_t *page = ((src[i] & 0x80) == 0) ? m_lowpage : m_highpage; + const char32_t *page = ((c & 0x80) == 0) ? m_lowpage : m_highpage; // is this page present? - if ((src[i] & 0x80) == 0) + if ((c & 0x80) == 0) { // no - pass it on - dest << src[i]; + dest << c; } else { // yes - we need to do a lookup - size_t base = ((src[i] & 0x80) == 0) ? 0x00 : 0x80; - char32_t ch = page[((unsigned char)(src[i])) - base]; + size_t base = ((c & 0x80) == 0) ? 0x00 : 0x80; + char32_t ch = page[((unsigned char)(c)) - base]; if (ch == 0) throw charconverter_exception(); diff --git a/src/tools/imgtool/charconv.h b/src/tools/imgtool/charconv.h index 1fe91385a2f..7df16f8a615 100644 --- a/src/tools/imgtool/charconv.h +++ b/src/tools/imgtool/charconv.h @@ -14,6 +14,10 @@ #include "unicode.h" +#include <sstream> +#include <utility> +#include <vector> + namespace imgtool { // ======================> charconverter @@ -22,11 +26,8 @@ namespace imgtool class charconverter { public: - virtual void from_utf8(std::ostream &dest, const char *src, size_t src_length) const = 0; - virtual void to_utf8(std::ostream &dest, const char *src, size_t src_length) const = 0; - - void from_utf8(std::ostream &dest, const std::string &src) const; - void to_utf8(std::ostream &dest, const std::string &src) const; + virtual void from_utf8(std::ostream &dest, std::string_view src) const = 0; + virtual void to_utf8(std::ostream &dest, std::string_view src) const = 0; std::string from_utf8(const std::string &src) const { @@ -59,8 +60,8 @@ namespace imgtool simple_charconverter(const char32_t lowpage[0x80], const char32_t highpage[0x80], unicode_normalization_form norm = unicode_normalization_form::C); - virtual void from_utf8(std::ostream &dest, const char *src, size_t src_length) const override; - virtual void to_utf8(std::ostream &dest, const char *src, size_t src_length) const override; + virtual void from_utf8(std::ostream &dest, std::string_view src) const override; + virtual void to_utf8(std::ostream &dest, std::string_view src) const override; private: std::vector<std::pair<char32_t, char> > m_reverse_lookup; diff --git a/src/tools/imgtool/filtbas.cpp b/src/tools/imgtool/filtbas.cpp index 37bf5f0ef71..f4098202c32 100644 --- a/src/tools/imgtool/filtbas.cpp +++ b/src/tools/imgtool/filtbas.cpp @@ -18,19 +18,21 @@ *****************************************************************************/ -#include <string.h> -#include <stdarg.h> -#include <ctype.h> +#include <cstring> +#include <cstdarg> +#include <cctype> #include "imgtool.h" -#include "formats/imageutl.h" +#include "filter.h" + +#include "multibyte.h" /*************************************************************************** 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))) @@ -51,7 +53,9 @@ struct basictoken_tableent struct basictokens { uint16_t baseaddress; + uint8_t size_pos; unsigned int skip_bytes : 15; + unsigned char bytes[20]; unsigned int be : 1; const basictoken_tableent *entries; int num_entries; @@ -75,7 +79,8 @@ static imgtoolerr_t basic_readfile(const basictokens *tokens, imgtoolerr_t err; imgtool::stream::ptr mem_stream; uint8_t line_header[4]; - uint16_t line_number; //, address; + [[maybe_unused]] uint16_t address; + uint16_t line_number; uint8_t b, shift; int i; int in_string = false; @@ -101,15 +106,13 @@ static imgtoolerr_t basic_readfile(const basictokens *tokens, /* pluck the address and line number out */ if (tokens->be) { - //address = (uint16_t) - pick_integer_be(line_header, 0, 2); - line_number = (uint16_t) pick_integer_be(line_header, 2, 2); + address = get_u16be(&line_header[0]); + line_number = get_u16be(&line_header[2]); } else { - //address = (uint16_t) - pick_integer_le(line_header, 0, 2); - line_number = (uint16_t) pick_integer_le(line_header, 2, 2); + address = get_u16le(&line_header[0]); + line_number = get_u16le(&line_header[2]); } /* write the line number */ @@ -181,7 +184,7 @@ static imgtoolerr_t basic_writefile(const basictokens *tokens, int i, j, pos, in_quotes; uint16_t line_number; uint8_t line_header[4]; - uint8_t file_header[3]; + uint8_t file_size[2]; const basictoken_tableent *token_table; const char *token; uint8_t token_shift, token_value; @@ -192,9 +195,8 @@ static imgtoolerr_t basic_writefile(const basictokens *tokens, if (!mem_stream) return IMGTOOLERR_OUTOFMEMORY; - /* skip first few bytes */ - mem_stream->fill(0x00, tokens->skip_bytes); - + /* write header */ + mem_stream->write(tokens->bytes, tokens->skip_bytes); /* loop until the file is complete */ while(!eof) { @@ -206,7 +208,7 @@ static imgtoolerr_t basic_writefile(const basictokens *tokens, if ((c == '\r') || (c == '\n')) break; - if (pos <= ARRAY_LENGTH(buf) - 1) + if (pos <= std::size(buf) - 1) { buf[pos++] = c; } @@ -242,13 +244,13 @@ static imgtoolerr_t basic_writefile(const basictokens *tokens, memset(&line_header, 0, sizeof(line_header)); if (tokens->be) { - place_integer_be(line_header, 0, 2, address); - place_integer_be(line_header, 2, 2, line_number); + put_u16be(&line_header[0], address); + put_u16be(&line_header[2], line_number); } else { - place_integer_le(line_header, 0, 2, address); - place_integer_le(line_header, 2, 2, line_number); + put_u16le(&line_header[0], address); + put_u16le(&line_header[2], line_number); } /* emit line header */ @@ -320,22 +322,20 @@ static imgtoolerr_t basic_writefile(const basictokens *tokens, mem_stream->fill(0x00, 2); /* reset stream */ - mem_stream->seek(0, SEEK_SET); + mem_stream->seek(tokens->size_pos, SEEK_SET); /* this is somewhat gross */ if (tokens->skip_bytes >= 3) { if (tokens->be) { - place_integer_be(file_header, 0, 1, 0xFF); - place_integer_be(file_header, 1, 2, mem_stream->size()); + put_u16be(file_size, mem_stream->size()); } else { - place_integer_le(file_header, 0, 1, 0xFF); - place_integer_le(file_header, 1, 2, mem_stream->size()); + put_u16le(file_size, mem_stream->size()); } - mem_stream->write(file_header, 3); + mem_stream->write(file_size, 2); mem_stream->seek(0, SEEK_SET); } @@ -603,25 +603,32 @@ static const char *const dragonbas_statements[] = "=", /* 0xcb */ "<", /* 0xcc */ "USING", /* 0xcd */ - "DIR", /* 0xce */ - "DRIVE", /* 0xcf */ - "FIELD", /* 0xd0 */ - "FILES", /* 0xd1 */ - "KILL", /* 0xd2 */ - "LOAD", /* 0xd3 */ - "LSET", /* 0xd4 */ - "MERGE", /* 0xd5 */ - "RENAME", /* 0xd6 */ - "RSET", /* 0xd7 */ - "SAVE", /* 0xd8 */ - "WRITE", /* 0xd9 */ - "VERIFY", /* 0xda */ - "UNLOAD", /* 0xdb */ - "DSKINI", /* 0xdc */ - "BACKUP", /* 0xdd */ - "COPY", /* 0xde */ - "DSKI$", /* 0xdf */ - "DSKO$" /* 0xe0 */ + "AUTO", /* 0xce */ + "BACKUP", /* 0xcf */ + "BEEP", /* 0xd0 */ + "BOOT", /* 0xd1 */ + "CHAIN", /* 0xd2 */ + "COPY", /* 0xd3 */ + "CREATE", /* 0xd4 */ + "DIR", /* 0xd5 */ + "DRIVE", /* 0xd6 */ + "DSKINIT", /* 0xd7 */ + "FREAD", /* 0xd8 */ + "FWRITE", /* 0xd9 */ + "ERROR", /* 0xda */ + "KILL", /* 0xdb */ + "LOAD", /* 0xdc */ + "MERGE", /* 0xdd */ + "PROTECT", /* 0xde */ + "WAIT", /* 0xdf */ + "RENAME", /* 0xe0 */ + "SAVE", /* 0xe1 */ + "SREAD", /* 0xe2 */ + "SWRITE", /* 0xe3 */ + "VERIFY", /* 0xe4 */ + "FROM", /* 0xe5 */ + "FLREAD", /* 0xe6 */ + "SWAP" /* 0xe7 */ }; static const char *const dragonbas_functions[] = @@ -660,11 +667,13 @@ static const char *const dragonbas_functions[] = "PPOINT", /* 0xff9f */ "STRING$", /* 0xffa0 */ "USR", /* 0xffa1 */ - "CVN", /* 0xffa2 */ + "LOF", /* 0xffa2 */ "FREE", /* 0xffa3 */ - "LOC", /* 0xffa4 */ - "LOF", /* 0xffa5 */ - "MKN$" /* 0xffa6 */ + "ERL", /* 0xffa4 */ + "ERR", /* 0xffa5 */ + "HIMEM", /* 0xffa6 */ + "LOC", /* 0xffa7 */ + "FRE$" /* 0xffa8 */ }; static const char *const vzbas[] = @@ -1024,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' */ }; @@ -1157,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' */ }; @@ -2935,17 +2944,19 @@ static const char *const basic_100[] = /* "BASIC 10.0" - supported by c65 & clon static const basictoken_tableent cocobas_tokenents[] = { - { 0x00, 0x80, cocobas_statements, ARRAY_LENGTH(cocobas_statements) }, - { 0xff, 0x80, cocobas_functions, ARRAY_LENGTH(cocobas_functions) } + { 0x00, 0x80, cocobas_statements, std::size(cocobas_statements) }, + { 0xff, 0x80, cocobas_functions, std::size(cocobas_functions) } }; static const basictokens cocobas_tokens = { 0x2600, + 1, 3, + {0xFF, 0x00, 0x00}, true, cocobas_tokenents, - ARRAY_LENGTH(cocobas_tokenents) + std::size(cocobas_tokenents) }; static imgtoolerr_t cocobas_readfile(imgtool::partition &partition, const char *filename, @@ -2960,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) { @@ -2979,17 +2990,19 @@ void filter_cocobas_getinfo(uint32_t state, union filterinfo *info) static const basictoken_tableent dragonbas_tokenents[] = { - { 0x00, 0x80, dragonbas_statements, ARRAY_LENGTH(dragonbas_statements) }, - { 0xff, 0x80, dragonbas_functions, ARRAY_LENGTH(dragonbas_functions) } + { 0x00, 0x80, dragonbas_statements, std::size(dragonbas_statements) }, + { 0xff, 0x80, dragonbas_functions, std::size(dragonbas_functions) } }; static const basictokens dragonbas_tokens = { - 0x2600, + 0x2415, 4, + 9, + {0x55, 0x01, 0x24, 0x01, 0x00, 0x2A, 0x8B, 0x8D, 0xAA}, true, dragonbas_tokenents, - ARRAY_LENGTH(dragonbas_tokenents) + std::size(dragonbas_tokenents) }; static imgtoolerr_t dragonbas_readfile(imgtool::partition &partition, const char *filename, @@ -3004,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) { @@ -3023,7 +3036,7 @@ void filter_dragonbas_getinfo(uint32_t state, union filterinfo *info) static const basictoken_tableent vzbas_tokenents[] = { - { 0x00, 0x80, vzbas, ARRAY_LENGTH(vzbas) } + { 0x00, 0x80, vzbas, std::size(vzbas) } }; @@ -3032,9 +3045,11 @@ static const basictokens vzbas_tokens = { 0x7ae9, 0, + 0, + {0x00}, false, vzbas_tokenents, - ARRAY_LENGTH(vzbas_tokenents) + std::size(vzbas_tokenents) }; static imgtoolerr_t vzbas_readfile(imgtool::partition &partition, const char *filename, @@ -3049,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) { @@ -3068,17 +3083,19 @@ void filter_vzbas_getinfo(uint32_t state, union filterinfo *info) static const basictoken_tableent bml3bas_tokenents[] = { - { 0x00, 0x80, bml3bas_statements, ARRAY_LENGTH(bml3bas_statements) }, - { 0xff, 0x80, bml3bas_functions, ARRAY_LENGTH(bml3bas_functions) } + { 0x00, 0x80, bml3bas_statements, std::size(bml3bas_statements) }, + { 0xff, 0x80, bml3bas_functions, std::size(bml3bas_functions) } }; static const basictokens bml3bas_tokens = { 0x2600, + 1, 3, + {0xFF, 0x00, 0x00}, true, bml3bas_tokenents, - ARRAY_LENGTH(bml3bas_tokenents) + std::size(bml3bas_tokenents) }; static imgtoolerr_t bml3bas_readfile(imgtool::partition &partition, const char *filename, @@ -3093,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 bb589e8fafe..41f11769747 100644 --- a/src/tools/imgtool/filteoln.cpp +++ b/src/tools/imgtool/filteoln.cpp @@ -8,11 +8,12 @@ *****************************************************************************/ -#include <string.h> - #include "imgtool.h" +#include "filter.h" + +#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))) @@ -95,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 e26c51a623b..9df7c3c1692 100644 --- a/src/tools/imgtool/filter.cpp +++ b/src/tools/imgtool/filter.cpp @@ -8,39 +8,39 @@ ***************************************************************************/ -#include <string.h> +#include "filter.h" -#include "imgtool.h" +#include <cstring> /* ----------------------------------------------------------------------- */ -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,12 +48,11 @@ 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, filter_dragonbas_getinfo, - filter_macbinary_getinfo, filter_vzsnapshot_getinfo, filter_vzbas_getinfo, filter_thombas5_getinfo, @@ -67,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 7ddd999c2a2..0b9b1f14884 100644 --- a/src/tools/imgtool/filter.h +++ b/src/tools/imgtool/filter.h @@ -8,11 +8,10 @@ ***************************************************************************/ -#ifndef FILTER_H -#define FILTER_H +#ifndef MAME_TOOLS_IMGTOOL_FILTER_H +#define MAME_TOOLS_IMGTOOL_FILTER_H -#include <stdlib.h> -#include <stdio.h> +#pragma once #include "library.h" @@ -37,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/formats/coco_dsk.cpp b/src/tools/imgtool/formats/coco_dsk.cpp index 6f509c92767..33363b2245e 100644 --- a/src/tools/imgtool/formats/coco_dsk.cpp +++ b/src/tools/imgtool/formats/coco_dsk.cpp @@ -8,14 +8,14 @@ *********************************************************************/ -#include <string.h> -#include <time.h> -#include <assert.h> +#include <cstring> +#include <ctime> +#include <cassert> #include "formats/coco_dsk.h" #include "formats/basicdsk.h" #include "formats/imageutl.h" -#include "coretmpl.h" +#include "opresolv.h" #include <algorithm> /* ----------------------------------------------------------------------- diff --git a/src/tools/imgtool/formats/coco_dsk.h b/src/tools/imgtool/formats/coco_dsk.h index 797911d40a1..bf9bccc5621 100644 --- a/src/tools/imgtool/formats/coco_dsk.h +++ b/src/tools/imgtool/formats/coco_dsk.h @@ -11,7 +11,7 @@ #ifndef COCO_DSK_H #define COCO_DSK_H -#include "formats/flopimg.h" +#include "formats/flopimg_legacy.h" /**************************************************************************/ diff --git a/src/tools/imgtool/formats/pc_dsk_legacy.cpp b/src/tools/imgtool/formats/pc_dsk_legacy.cpp new file mode 100644 index 00000000000..771f0de8638 --- /dev/null +++ b/src/tools/imgtool/formats/pc_dsk_legacy.cpp @@ -0,0 +1,140 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +/********************************************************************* + + formats/pc_dsk_legacy.cpp + + PC disk images (legacy support for imgtool) + +*********************************************************************/ + +#include "formats/pc_dsk_legacy.h" +#include "formats/basicdsk.h" + +#include "opresolv.h" + +struct pc_disk_sizes +{ + uint32_t image_size; + int sectors; + int heads; +}; + + + +static const struct pc_disk_sizes disk_sizes[] = +{ + { 8*1*40*512, 8, 1}, /* 5 1/4 inch double density single sided */ + { 8*2*40*512, 8, 2}, /* 5 1/4 inch double density */ + { 9*1*40*512, 9, 1}, /* 5 1/4 inch double density single sided */ + { 9*2*40*512, 9, 2}, /* 5 1/4 inch double density */ + {10*2*40*512, 10, 2}, /* 5 1/4 inch double density single sided */ + { 9*2*80*512, 9, 2}, /* 80 tracks 5 1/4 inch drives rare in PCs */ + { 9*2*80*512, 9, 2}, /* 3 1/2 inch double density */ + {15*2*80*512, 15, 2}, /* 5 1/4 inch high density (or japanese 3 1/2 inch high density) */ + {18*2*80*512, 18, 2}, /* 3 1/2 inch high density */ + {21*2*80*512, 21, 2}, /* 3 1/2 inch high density DMF */ + {36*2*80*512, 36, 2} /* 3 1/2 inch enhanced density */ +}; + + + +static floperr_t pc_dsk_compute_geometry(floppy_image_legacy *floppy, struct basicdsk_geometry *geometry) +{ + int i; + uint64_t size; + + memset(geometry, 0, sizeof(*geometry)); + size = floppy_image_size(floppy); + + for (i = 0; i < std::size(disk_sizes); i++) + { + if (disk_sizes[i].image_size == size) + { + geometry->sectors = disk_sizes[i].sectors; + geometry->heads = disk_sizes[i].heads; + geometry->sector_length = 512; + geometry->first_sector_id = 1; + geometry->tracks = (int) (size / disk_sizes[i].sectors / disk_sizes[i].heads / geometry->sector_length); + return FLOPPY_ERROR_SUCCESS; + } + } + + if (size >= 0x1a) + { + /* + * get info from boot sector. + * not correct on all disks + */ + uint8_t scl, spt, heads; + floppy_image_read(floppy, &scl, 0x0c, 1); + floppy_image_read(floppy, &spt, 0x18, 1); + floppy_image_read(floppy, &heads, 0x1A, 1); + + if (size == ((uint64_t) scl) * spt * heads * 0x200) + { + geometry->sectors = spt; + geometry->heads = heads; + geometry->sector_length = 512; + geometry->first_sector_id = 1; + geometry->tracks = scl; + return FLOPPY_ERROR_SUCCESS; + } + } + + return FLOPPY_ERROR_SUCCESS; +} + + + +static FLOPPY_IDENTIFY(pc_dsk_identify) +{ + floperr_t err; + struct basicdsk_geometry geometry; + + err = pc_dsk_compute_geometry(floppy, &geometry); + if (err) + return err; + + *vote = geometry.heads ? 100 : 0; + return FLOPPY_ERROR_SUCCESS; +} + + + +static FLOPPY_CONSTRUCT(pc_dsk_construct) +{ + floperr_t err; + struct basicdsk_geometry geometry; + + if (params) + { + /* create */ + memset(&geometry, 0, sizeof(geometry)); + geometry.heads = params->lookup_int(PARAM_HEADS); + geometry.tracks = params->lookup_int(PARAM_TRACKS); + geometry.sectors = params->lookup_int(PARAM_SECTORS); + geometry.first_sector_id = 1; + geometry.sector_length = 512; + } + else + { + /* open */ + err = pc_dsk_compute_geometry(floppy, &geometry); + if (err) + return err; + } + + return basicdsk_construct(floppy, &geometry); +} + + + +/* ----------------------------------------------------------------------- */ + +LEGACY_FLOPPY_OPTIONS_START( pc ) + LEGACY_FLOPPY_OPTION( pc_dsk, "dsk,ima,img,ufi,360", "PC floppy disk image", pc_dsk_identify, pc_dsk_construct, nullptr, + HEADS([1]-2) + TRACKS(40/[80]) + SECTORS(8/[9]/10/15/18/36)) +LEGACY_FLOPPY_OPTIONS_END diff --git a/src/tools/imgtool/formats/pc_dsk_legacy.h b/src/tools/imgtool/formats/pc_dsk_legacy.h new file mode 100644 index 00000000000..14cb33f389d --- /dev/null +++ b/src/tools/imgtool/formats/pc_dsk_legacy.h @@ -0,0 +1,21 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +/********************************************************************* + + formats/pc_dsk_legacy.h + + PC disk images (legacy support for imgtool) + +*********************************************************************/ + +#ifndef PC_DSK_LEGACY_H +#define PC_DSK_LEGACY_H + +#include "formats/flopimg_legacy.h" + + +/**************************************************************************/ + +LEGACY_FLOPPY_OPTIONS_EXTERN(pc); + +#endif /* PC_DSK_LEGACY_H */ diff --git a/src/tools/imgtool/formats/vt_dsk.cpp b/src/tools/imgtool/formats/vt_dsk_legacy.cpp index 02f74668b0f..6cf57856574 100644 --- a/src/tools/imgtool/formats/vt_dsk.cpp +++ b/src/tools/imgtool/formats/vt_dsk_legacy.cpp @@ -2,18 +2,19 @@ // copyright-holders:Juergen Buchmueller /********************************************************************* - formats/vt_dsk.c + formats/vt_dsk_legacy.cpp - VTech Laser/VZ disk images + VTech Laser/VZ disk images (legacy support) *********************************************************************/ -#include <stdio.h> -#include <string.h> -#include <assert.h> -#include "formats/vt_dsk.h" +#include "formats/vt_dsk_legacy.h" #include "formats/basicdsk.h" +#include "opresolv.h" + +#include <cstring> + static FLOPPY_IDENTIFY(vz_identify) { uint64_t size = floppy_image_size(floppy); diff --git a/src/tools/imgtool/formats/vt_dsk.h b/src/tools/imgtool/formats/vt_dsk_legacy.h index a3f9a86b44e..fe8f0ddf6a3 100644 --- a/src/tools/imgtool/formats/vt_dsk.h +++ b/src/tools/imgtool/formats/vt_dsk_legacy.h @@ -2,17 +2,17 @@ // copyright-holders:Juergen Buchmueller /********************************************************************* - formats/vt_dsk.h + formats/vt_dsk_legacy.h - Tandy Color Computer / Dragon disk images + VTech Laser/VZ disk images (legacy support) *********************************************************************/ -#ifndef VT_DSK_H -#define VT_DSK_H +#ifndef VT_DSK_LEGACY_H +#define VT_DSK_LEGACY_H -#include "formats/flopimg.h" +#include "formats/flopimg_legacy.h" LEGACY_FLOPPY_OPTIONS_EXTERN(vz); -#endif /* VT_DSK_H */ +#endif /* VT_DSK_LEGACY_H */ diff --git a/src/tools/imgtool/iflopimg.cpp b/src/tools/imgtool/iflopimg.cpp index f6e79e6cd5d..2d785c92a0d 100644 --- a/src/tools/imgtool/iflopimg.cpp +++ b/src/tools/imgtool/iflopimg.cpp @@ -8,10 +8,15 @@ *********************************************************************/ +#include "iflopimg.h" + #include "imgtool.h" -#include "formats/flopimg.h" #include "library.h" -#include "iflopimg.h" + +#include "ioprocs.h" + +#include <cstdio> + imgtoolerr_t imgtool_floppy_error(floperr_t err) { @@ -40,57 +45,6 @@ imgtoolerr_t imgtool_floppy_error(floperr_t err) /********************************************************************* - Imgtool ioprocs -*********************************************************************/ - -static void imgtool_floppy_closeproc(void *file) -{ - delete reinterpret_cast<imgtool::stream *>(file); -} - -static int imgtool_floppy_seekproc(void *file, int64_t offset, int whence) -{ - reinterpret_cast<imgtool::stream *>(file)->seek(offset, whence); - return 0; -} - -static size_t imgtool_floppy_readproc(void *file, void *buffer, size_t length) -{ - return reinterpret_cast<imgtool::stream *>(file)->read(buffer, length); -} - -static size_t imgtool_floppy_writeproc(void *file, const void *buffer, size_t length) -{ - reinterpret_cast<imgtool::stream *>(file)->write(buffer, length); - return length; -} - -static uint64_t imgtool_floppy_filesizeproc(void *file) -{ - return reinterpret_cast<imgtool::stream *>(file)->size(); -} - -static const struct io_procs imgtool_ioprocs = -{ - imgtool_floppy_closeproc, - imgtool_floppy_seekproc, - imgtool_floppy_readproc, - imgtool_floppy_writeproc, - imgtool_floppy_filesizeproc -}; - -static const struct io_procs imgtool_noclose_ioprocs = -{ - nullptr, - imgtool_floppy_seekproc, - imgtool_floppy_readproc, - imgtool_floppy_writeproc, - imgtool_floppy_filesizeproc -}; - - - -/********************************************************************* Imgtool handlers *********************************************************************/ @@ -102,11 +56,10 @@ struct imgtool_floppy_image -static imgtoolerr_t imgtool_floppy_open_internal(imgtool::image &image, imgtool::stream::ptr &&stream, int noclose) +static imgtoolerr_t imgtool_floppy_open_internal(imgtool::image &image, imgtool::stream::ptr &&stream) { floperr_t ferr; imgtoolerr_t err = IMGTOOLERR_SUCCESS; - imgtool::stream *f = nullptr; struct imgtool_floppy_image *fimg; const imgtool_class *imgclass; const struct FloppyFormat *format; @@ -117,18 +70,13 @@ static imgtoolerr_t imgtool_floppy_open_internal(imgtool::image &image, imgtool: format = (const struct FloppyFormat *) imgclass->derived_param; open = (imgtoolerr_t (*)(imgtool::image &, imgtool::stream *)) imgtool_get_info_ptr(imgclass, IMGTOOLINFO_PTR_FLOPPY_OPEN); - // extract the pointer - f = stream.release(); - // open up the floppy - ferr = floppy_open(f, noclose ? &imgtool_noclose_ioprocs : &imgtool_ioprocs, - "", format, FLOPPY_FLAGS_READWRITE, &fimg->floppy); + ferr = floppy_open(imgtool::stream_read_write(std::move(stream), 0xff), "", format, FLOPPY_FLAGS_READWRITE, &fimg->floppy); if (ferr) { err = imgtool_floppy_error(ferr); goto done; } - f = nullptr; // the floppy object has the stream now if (open) { @@ -138,8 +86,6 @@ static imgtoolerr_t imgtool_floppy_open_internal(imgtool::image &image, imgtool: } done: - if (f) - delete f; if (err && fimg->floppy) { floppy_close(fimg->floppy); @@ -152,7 +98,7 @@ done: static imgtoolerr_t imgtool_floppy_open(imgtool::image &image, imgtool::stream::ptr &&stream) { - return imgtool_floppy_open_internal(image, std::move(stream), false); + return imgtool_floppy_open_internal(image, std::move(stream)); } @@ -161,7 +107,6 @@ static imgtoolerr_t imgtool_floppy_create(imgtool::image &image, imgtool::stream { floperr_t ferr; imgtoolerr_t err = IMGTOOLERR_SUCCESS; - imgtool::stream *f = nullptr; struct imgtool_floppy_image *fimg; const imgtool_class *imgclass; const struct FloppyFormat *format; @@ -174,17 +119,13 @@ static imgtoolerr_t imgtool_floppy_create(imgtool::image &image, imgtool::stream create = (imgtoolerr_t (*)(imgtool::image &, imgtool::stream *, util::option_resolution *)) imgtool_get_info_ptr(imgclass, IMGTOOLINFO_PTR_FLOPPY_CREATE); open = (imgtoolerr_t (*)(imgtool::image &, imgtool::stream *)) imgtool_get_info_ptr(imgclass, IMGTOOLINFO_PTR_FLOPPY_OPEN); - // extract the pointer - f = stream.release(); - // open up the floppy - ferr = floppy_create(f, &imgtool_ioprocs, format, opts, &fimg->floppy); + ferr = floppy_create(imgtool::stream_read_write(std::move(stream), 0xff), format, opts, &fimg->floppy); if (ferr) { err = imgtool_floppy_error(ferr); goto done; } - f = nullptr; // the floppy object has the stream now // do we have to do extra stuff when creating the image? if (create) @@ -203,8 +144,6 @@ static imgtoolerr_t imgtool_floppy_create(imgtool::image &image, imgtool::stream } done: - if (f) - delete f; if (err && fimg->floppy) { floppy_close(fimg->floppy); @@ -292,7 +231,7 @@ static void imgtool_floppy_get_info(const imgtool_class *imgclass, uint32_t stat case IMGTOOLINFO_PTR_OPEN: info->open = imgtool_floppy_open; break; case IMGTOOLINFO_PTR_CREATE: info->create = imgtool_floppy_create; break; case IMGTOOLINFO_PTR_CLOSE: info->close = imgtool_floppy_close; break; - case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE: info->createimage_optguide = format->param_guidelines ? &floppy_option_guide : nullptr; break; + case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE: info->createimage_optguide = format->param_guidelines ? &floppy_option_guide() : nullptr; break; case IMGTOOLINFO_PTR_READ_SECTOR: info->read_sector = imgtool_floppy_read_sector; break; case IMGTOOLINFO_PTR_WRITE_SECTOR: info->write_sector = imgtool_floppy_write_sector; break; diff --git a/src/tools/imgtool/iflopimg.h b/src/tools/imgtool/iflopimg.h index 078a1247ae3..43bbb1ecda3 100644 --- a/src/tools/imgtool/iflopimg.h +++ b/src/tools/imgtool/iflopimg.h @@ -7,13 +7,16 @@ Bridge code for Imgtool into the standard floppy code *********************************************************************/ +#ifndef MAME_TOOLS_IMGTOOL_IFLOPIMG_H +#define MAME_TOOLS_IMGTOOL_IFLOPIMG_H -#ifndef IFLOPIMG_H -#define IFLOPIMG_H +#pragma once -#include "formats/flopimg.h" #include "library.h" +#include "formats/flopimg_legacy.h" + + /*************************************************************************** Prototypes @@ -38,4 +41,4 @@ imgtoolerr_t imgtool_floppy_write_sector_from_stream(imgtool::image &img, int he void *imgtool_floppy_extrabytes(imgtool::image &img); -#endif /* IFLOPIMG_H */ +#endif // MAME_TOOLS_IMGTOOL_IFLOPIMG_H diff --git a/src/tools/imgtool/imghd.cpp b/src/tools/imgtool/imghd.cpp index b868b692c63..60a79469051 100644 --- a/src/tools/imgtool/imghd.cpp +++ b/src/tools/imgtool/imghd.cpp @@ -9,34 +9,24 @@ Raphael Nabet 2003 */ -#include "imgtool.h" -#include "harddisk.h" #include "imghd.h" +#include "library.h" +#include "stream.h" +#include "harddisk.h" +#include "opresolv.h" -static imgtoolerr_t map_chd_error(chd_error chderr) -{ - imgtoolerr_t err; - switch(chderr) - { - case CHDERR_NONE: - err = IMGTOOLERR_SUCCESS; - break; - case CHDERR_OUT_OF_MEMORY: - err = IMGTOOLERR_OUTOFMEMORY; - break; - case CHDERR_FILE_NOT_WRITEABLE: - err = IMGTOOLERR_READONLY; - break; - case CHDERR_NOT_SUPPORTED: - err = IMGTOOLERR_UNIMPLEMENTED; - break; - default: - err = IMGTOOLERR_UNEXPECTED; - break; - } - return err; +static imgtoolerr_t map_chd_error(std::error_condition chderr) +{ + if (!chderr) + return IMGTOOLERR_SUCCESS; + else if (std::errc::not_enough_memory == chderr) + return IMGTOOLERR_OUTOFMEMORY; + else if (chd_file::error::FILE_NOT_WRITEABLE == chderr) + return IMGTOOLERR_READONLY; + else + return IMGTOOLERR_UNEXPECTED; } @@ -50,7 +40,7 @@ imgtoolerr_t imghd_create(imgtool::stream &stream, uint32_t hunksize, uint32_t c { imgtoolerr_t err = IMGTOOLERR_SUCCESS; chd_file chd; - chd_error rc; + std::error_condition rc; chd_codec_type compression[4] = { CHD_CODEC_NONE }; /* sanity check args -- see parse_hunk_size() in src/lib/util/chd.cpp */ @@ -73,17 +63,17 @@ imgtoolerr_t imghd_create(imgtool::stream &stream, uint32_t hunksize, uint32_t c const uint64_t logicalbytes = (uint64_t)cylinders * heads * sectors * seclen; /* create the new hard drive */ - rc = chd.create(*stream.core_file(), logicalbytes, hunksize, seclen, compression); - if (rc != CHDERR_NONE) + rc = chd.create(stream_read_write(stream, 0), logicalbytes, hunksize, seclen, compression); + if (rc) { err = map_chd_error(rc); return err; } /* write the metadata */ - const std::string metadata = string_format(HARD_DISK_METADATA_FORMAT, cylinders, heads, sectors, seclen); - err = (imgtoolerr_t)chd.write_metadata(HARD_DISK_METADATA_TAG, 0, metadata); - if (rc != CHDERR_NONE) + const std::string metadata = util::string_format(HARD_DISK_METADATA_FORMAT, cylinders, heads, sectors, seclen); + rc = chd.write_metadata(HARD_DISK_METADATA_TAG, 0, metadata); + if (rc) { err = map_chd_error(rc); return err; @@ -118,19 +108,19 @@ imgtoolerr_t imghd_create(imgtool::stream &stream, uint32_t hunksize, uint32_t c */ imgtoolerr_t imghd_open(imgtool::stream &stream, struct mess_hard_disk_file *hard_disk) { - chd_error chderr; + std::error_condition chderr; imgtoolerr_t err = IMGTOOLERR_SUCCESS; hard_disk->hard_disk = nullptr; - chderr = hard_disk->chd.open(*stream.core_file(), !stream.is_read_only()); + chderr = hard_disk->chd.open(stream_read_write(stream, 0), !stream.is_read_only()); if (chderr) { err = map_chd_error(chderr); goto done; } - hard_disk->hard_disk = hard_disk_open(&hard_disk->chd); + hard_disk->hard_disk = new hard_disk_file(&hard_disk->chd); if (!hard_disk->hard_disk) { err = IMGTOOLERR_UNEXPECTED; @@ -155,7 +145,7 @@ void imghd_close(struct mess_hard_disk_file *disk) { if (disk->hard_disk) { - hard_disk_close(disk->hard_disk); + delete disk->hard_disk; disk->hard_disk = nullptr; } if (disk->stream) @@ -174,9 +164,8 @@ void imghd_close(struct mess_hard_disk_file *disk) */ imgtoolerr_t imghd_read(struct mess_hard_disk_file *disk, uint32_t lbasector, void *buffer) { - uint32_t reply; - reply = hard_disk_read(disk->hard_disk, lbasector, buffer); - return (imgtoolerr_t)(reply ? IMGTOOLERR_SUCCESS : map_chd_error((chd_error)reply)); + uint32_t reply = disk->hard_disk->read(lbasector, buffer); + return reply ? IMGTOOLERR_SUCCESS : IMGTOOLERR_READERROR; } @@ -188,9 +177,8 @@ imgtoolerr_t imghd_read(struct mess_hard_disk_file *disk, uint32_t lbasector, vo */ imgtoolerr_t imghd_write(struct mess_hard_disk_file *disk, uint32_t lbasector, const void *buffer) { - uint32_t reply; - reply = hard_disk_write(disk->hard_disk, lbasector, buffer); - return (imgtoolerr_t)(reply ? IMGTOOLERR_SUCCESS : map_chd_error((chd_error)reply)); + uint32_t reply = disk->hard_disk->write(lbasector, buffer); + return reply ? IMGTOOLERR_SUCCESS : IMGTOOLERR_WRITEERROR; } @@ -200,11 +188,9 @@ imgtoolerr_t imghd_write(struct mess_hard_disk_file *disk, uint32_t lbasector, c Return pointer to the header of MAME HD image */ -const hard_disk_info *imghd_get_header(struct mess_hard_disk_file *disk) +const hard_disk_file::info &imghd_get_header(struct mess_hard_disk_file *disk) { - const hard_disk_info *reply; - reply = hard_disk_get_info(disk->hard_disk); - return reply; + return disk->hard_disk->get_info(); } diff --git a/src/tools/imgtool/imghd.h b/src/tools/imgtool/imghd.h index d4ae341af1e..c49e87fe8db 100644 --- a/src/tools/imgtool/imghd.h +++ b/src/tools/imgtool/imghd.h @@ -11,8 +11,17 @@ #ifndef IMGHD_H #define IMGHD_H +#include "imgterrs.h" + +#include "chd.h" #include "harddisk.h" + +namespace imgtool +{ + class stream; +} + struct mess_hard_disk_file { imgtool::stream *stream; @@ -37,6 +46,6 @@ imgtoolerr_t imghd_read(struct mess_hard_disk_file *disk, uint32_t lbasector, vo imgtoolerr_t imghd_write(struct mess_hard_disk_file *disk, uint32_t lbasector, const void *buffer); /* gets the header from a hard disk */ -const hard_disk_info *imghd_get_header(struct mess_hard_disk_file *disk); +const hard_disk_file::info &imghd_get_header(struct mess_hard_disk_file *disk); #endif /* IMGHD_H */ diff --git a/src/tools/imgtool/imgterrs.cpp b/src/tools/imgtool/imgterrs.cpp index bd679440309..9018ed79170 100644 --- a/src/tools/imgtool/imgterrs.cpp +++ b/src/tools/imgtool/imgterrs.cpp @@ -8,9 +8,10 @@ ***************************************************************************/ -#include "imgtool.h" #include "imgterrs.h" -#include "osdcomm.h" + +#include <cassert> +#include <iterator> static const char *const msgs[] = { @@ -50,6 +51,6 @@ const char *imgtool_error(imgtoolerr_t err) { err = (imgtoolerr_t)(ERRORCODE(err) - 1); assert(err >= 0); - assert(err < ARRAY_LENGTH(msgs)); + assert(err < std::size(msgs)); return msgs[err]; } diff --git a/src/tools/imgtool/imgtool.cpp b/src/tools/imgtool/imgtool.cpp index b51d7b4d478..e10558dcce1 100644 --- a/src/tools/imgtool/imgtool.cpp +++ b/src/tools/imgtool/imgtool.cpp @@ -8,15 +8,25 @@ ***************************************************************************/ -#include <string.h> -#include <ctype.h> -#include <iostream> - #include "imgtool.h" -#include "formats/imageutl.h" +#include "charconv.h" +#include "filter.h" #include "library.h" #include "modules.h" -#include "pool.h" + +#include "formats/imageutl.h" + +#include "corestr.h" +#include "opresolv.h" +#include "path.h" +#include "strformat.h" + +#include <cstdarg> +#include <cstdio> +#include <cstring> +#include <cctype> +#include <iostream> + /*************************************************************************** @@ -83,10 +93,11 @@ char *strncpyz(char *dest, const char *source, size_t len) // extract_padded_string //------------------------------------------------- -static std::string extract_padded_string(const char *source, size_t len) +static std::string extract_padded_string(const char *source, size_t len, char pad) { - while ((len > 0) && (source[len - 1] == ' ')) + while ((len > 0) && (source[len - 1] == pad)) len--; + return std::string(source, len); } @@ -97,10 +108,10 @@ static std::string extract_padded_string(const char *source, size_t len) // this in common code //------------------------------------------------- -std::string extract_padded_filename(const char *source, size_t filename_length, size_t extension_length) +std::string extract_padded_filename(const char *source, size_t filename_length, size_t extension_length, char pad) { - std::string filename = extract_padded_string(source, filename_length); - std::string extension = extract_padded_string(source + filename_length, extension_length); + std::string filename = extract_padded_string(source, filename_length, pad); + std::string extension = extract_padded_string(source + filename_length, extension_length, pad); return extension.empty() ? filename : filename + "." + extension; } @@ -139,7 +150,7 @@ static imgtoolerr_t markerrorsource(imgtoolerr_t err) static void internal_error(const imgtool_module *module, const char *message) { #ifdef MAME_DEBUG - printf("%s: %s\n", module->name, message); + printf("%s: %s\n", module->name.c_str(), message); #endif } @@ -249,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; + + 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; + result = current_result; + } } done: @@ -334,7 +339,7 @@ imgtoolerr_t imgtool::image::identify_file(const char *fname, imgtool_module **m /* iterate through all modules */ for (const auto &module : library.modules()) { - if (!extension || image_find_extension(module->extensions, extension)) + if (!extension || image_find_extension(module->extensions.c_str(), extension)) { err = evaluate_module(fname, module.get(), val); if (err) @@ -532,16 +537,6 @@ imgtoolerr_t imgtool::image::list_partitions(std::vector<imgtool::partition_info } -//------------------------------------------------- -// malloc - allocates memory associated with an image -//------------------------------------------------- - -void *imgtool::image::malloc(size_t size) -{ - return pool_malloc_lib(m_pool, size); -} - - /*************************************************************************** Imgtool partition management @@ -588,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); @@ -849,17 +844,17 @@ bool imgtool_validitychecks(void) { features = imgtool_get_module_features(module.get()); - if (!module->name) + if (module->name.empty()) { - util::stream_format(std::wcerr, L"imgtool module %s has null 'name'\n", wstring_from_utf8(module->name)); + util::stream_format(std::wcerr, L"imgtool module has null 'name'\n"); error = true; } - if (!module->description) + if (module->description.empty()) { util::stream_format(std::wcerr, L"imgtool module %s has null 'description'\n", wstring_from_utf8(module->name)); error = true; } - if (!module->extensions) + if (module->extensions.empty()) { util::stream_format(std::wcerr, L"imgtool module %s has null 'extensions'\n", wstring_from_utf8(module->extensions)); error = true; @@ -893,24 +888,24 @@ bool imgtool_validitychecks(void) #endif /* sanity checks on creation options */ - if (module->createimage_optguide || module->createimage_optspec) + if (module->createimage_optguide || !module->createimage_optspec.empty()) { if (!module->create) { util::stream_format(std::wcerr, L"imgtool module %s has creation options without supporting create\n", wstring_from_utf8(module->name)); error = true; } - if ((!module->createimage_optguide && module->createimage_optspec) - || (module->createimage_optguide && !module->createimage_optspec)) + if ((!module->createimage_optguide && !module->createimage_optspec.empty()) + || (module->createimage_optguide && module->createimage_optspec.empty())) { - util::stream_format(std::wcerr, L"imgtool module %s does has partially incomplete creation options\n", wstring_from_utf8(module->name)); + util::stream_format(std::wcerr, L"imgtool module %s has partially incomplete creation options\n", wstring_from_utf8(module->name)); error = true; } - if (module->createimage_optguide && module->createimage_optspec) + if (module->createimage_optguide && !module->createimage_optspec.empty()) { auto resolution = std::make_unique<util::option_resolution>(*module->createimage_optguide); - resolution->set_specification(module->createimage_optspec); + resolution->set_specification(module->createimage_optspec.c_str()); } } } @@ -936,7 +931,7 @@ char *imgtool_temp_str(void) { static int index; static char temp_string_pool[32][256]; - return temp_string_pool[index++ % ARRAY_LENGTH(temp_string_pool)]; + return temp_string_pool[index++ % std::size(temp_string_pool)]; } @@ -953,8 +948,6 @@ imgtoolerr_t imgtool::image::internal_open(const imgtool_module *module, const s imgtoolerr_t err; imgtool::stream::ptr stream; imgtool::image::ptr image; - object_pool *pool = nullptr; - void *extra_bytes = nullptr; outimg.reset(); @@ -965,14 +958,6 @@ imgtoolerr_t imgtool::image::internal_open(const imgtool_module *module, const s goto done; } - // create a memory pool - pool = pool_alloc_lib(nullptr); - if (!pool) - { - err = imgtoolerr_t(IMGTOOLERR_OUTOFMEMORY); - goto done; - } - // open the stream stream = imgtool::stream::open(filename, read_or_write); if (!stream) @@ -981,29 +966,14 @@ imgtoolerr_t imgtool::image::internal_open(const imgtool_module *module, const s goto done; } - // allocate extra - if (module->image_extra_bytes > 0) - { - extra_bytes = pool_malloc_lib(pool, module->image_extra_bytes); - if (!extra_bytes) - { - err = imgtoolerr_t(IMGTOOLERR_OUTOFMEMORY); - goto done; - } - memset(extra_bytes, 0, module->image_extra_bytes); - } - // setup the image structure - try { image = std::make_unique<imgtool::image>(*module, pool, extra_bytes); } + try { image = std::make_unique<imgtool::image>(*module); } catch (std::bad_alloc const &) { err = imgtoolerr_t(IMGTOOLERR_OUTOFMEMORY); goto done; } - // the pool is no longer owned by this function - pool = nullptr; - // actually call create or open err = (read_or_write == OSD_FOPEN_RW_CREATE) ? module->create(*image, std::move(stream), createopts) @@ -1020,8 +990,6 @@ imgtoolerr_t imgtool::image::internal_open(const imgtool_module *module, const s outimg = std::move(image); done: - if (pool) - pool_free_lib(pool); return err; } @@ -1057,12 +1025,16 @@ imgtoolerr_t imgtool::image::open(const std::string &modulename, const std::stri // imgtool::image::image //------------------------------------------------- -imgtool::image::image(const imgtool_module &module, object_pool *pool, void *extra_bytes) +imgtool::image::image(const imgtool_module &module) : m_module(module) - , m_pool(pool) - , m_extra_bytes(extra_bytes) , m_okay_to_close(false) { + if (module.image_extra_bytes > 0) + { + m_extra_bytes = std::make_unique<uint8_t[]>(module.image_extra_bytes); + std::fill_n(&m_extra_bytes[0], module.image_extra_bytes, 0); + } + } @@ -1074,7 +1046,6 @@ imgtool::image::~image() { if (m_okay_to_close && module().close) module().close(*this); - pool_free_lib(m_pool); } @@ -1093,8 +1064,8 @@ imgtoolerr_t imgtool::image::create(const imgtool_module *module, const std::str try { alloc_resolution.reset(new util::option_resolution(*module->createimage_optguide)); } catch (...) { return (imgtoolerr_t)IMGTOOLERR_OUTOFMEMORY; } - if (module->createimage_optspec) - alloc_resolution->set_specification(module->createimage_optspec); + if (!module->createimage_optspec.empty()) + alloc_resolution->set_specification(module->createimage_optspec.c_str()); opts = alloc_resolution.get(); } @@ -1316,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; } @@ -1489,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); @@ -1516,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) @@ -1552,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; } @@ -1563,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; @@ -1592,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; @@ -1602,7 +1563,7 @@ imgtoolerr_t imgtool::partition::get_chain_string(const char *path, char *buffer chain[0].block = ~0; last_block = chain[0].block; - err = get_chain(path, chain, ARRAY_LENGTH(chain)); + err = get_chain(path, chain, std::size(chain)); if (err) return err; @@ -1883,7 +1844,7 @@ imgtoolerr_t imgtool::partition::put_file(const char *newfname, const char *fork if (!newfname) { - basename = core_filename_extract_base(source); + basename = std::string(core_filename_extract_base(source)); newfname = basename.c_str(); } @@ -2276,7 +2237,7 @@ imgtool::directory::directory(imgtool::partition &partition) if (partition.m_directory_extra_bytes > 0) { m_extra_bytes = std::make_unique<uint8_t[]>(partition.m_directory_extra_bytes); - memset(m_extra_bytes.get(), 0, sizeof(m_extra_bytes.get()[0] * partition.m_directory_extra_bytes)); + memset(m_extra_bytes.get(), 0, sizeof(m_extra_bytes[0]) * partition.m_directory_extra_bytes); } } @@ -2341,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) @@ -2361,7 +2321,7 @@ imgtoolerr_t imgtool::directory::get_next(imgtool_dirent &ent) { return imgtoolerr_t(IMGTOOLERR_BADFILENAME); } - snprintf(ent.filename, ARRAY_LENGTH(ent.filename), "%s", new_fname.c_str()); + snprintf(ent.filename, std::size(ent.filename), "%s", new_fname.c_str()); } // don't trust the module! @@ -2393,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 aa4ae79e29e..4ad7fc5479d 100644 --- a/src/tools/imgtool/imgtool.h +++ b/src/tools/imgtool/imgtool.h @@ -8,19 +8,19 @@ ***************************************************************************/ -#ifndef IMGTOOL_H -#define IMGTOOL_H +#ifndef MAME_TOOLS_IMGTOOL_IMGTOOL_H +#define MAME_TOOLS_IMGTOOL_IMGTOOL_H -#include <stdlib.h> -#include <stdio.h> -#include <assert.h> -#include <functional> +#pragma once -#include "corestr.h" -#include "formats/flopimg.h" -#include "opresolv.h" #include "library.h" -#include "filter.h" +#include "stream.h" + +#include "osdcomm.h" + +#include <cassert> +#include <cstdlib> +#include <functional> /* ----------------------------------------------------------------------- */ @@ -94,7 +94,7 @@ namespace imgtool public: typedef std::unique_ptr<image> ptr; - image(const imgtool_module &module, object_pool *pool, void *extra_bytes); + image(const imgtool_module &module); ~image(); static imgtoolerr_t identify_file(const char *filename, imgtool_module **modules, size_t count); @@ -114,14 +114,12 @@ namespace imgtool imgtoolerr_t write_block(uint64_t block, const void *buffer); imgtoolerr_t clear_block(uint64_t block, uint8_t data); imgtoolerr_t list_partitions(std::vector<imgtool::partition_info> &partitions); - void *malloc(size_t size); const imgtool_module &module() { return m_module; } - void *extra_bytes() { return m_extra_bytes; } + void *extra_bytes() { return m_extra_bytes.get(); } private: const imgtool_module &m_module; - object_pool *m_pool; - void *m_extra_bytes; + std::unique_ptr<uint8_t[]> m_extra_bytes; // because of an idiosyncrasy of how imgtool::image::internal_open() works, we are only "okay to close" // by invoking the module's close function once internal_open() succeeds. the long term solution is @@ -168,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); @@ -217,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; @@ -264,6 +262,6 @@ void unknown_partition_get_info(const imgtool_class *imgclass, uint32_t state, u 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); +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.cpp b/src/tools/imgtool/library.cpp index 785054575b0..3b05d947a49 100644 --- a/src/tools/imgtool/library.cpp +++ b/src/tools/imgtool/library.cpp @@ -9,12 +9,12 @@ ****************************************************************************/ -#include <string.h> -#include <algorithm> - -#include "imgtool.h" #include "library.h" -#include "pool.h" + +#include "corestr.h" + +#include <algorithm> +#include <cstring> namespace imgtool { @@ -145,9 +145,6 @@ time_t datetime::to_time_t() const library::library() { - m_pool = pool_alloc_lib(nullptr); - if (!m_pool) - throw std::bad_alloc(); } @@ -157,7 +154,6 @@ library::library() library::~library() { - pool_free_lib(m_pool); } @@ -167,30 +163,25 @@ library::~library() void library::add_class(const imgtool_class *imgclass) { - char *s1, *s2; + char const *temp; // allocate the module and place it in the chain m_modules.emplace_back(std::make_unique<imgtool_module>()); imgtool_module *module = m_modules.back().get(); - memset(module, 0, sizeof(*module)); - - // extensions have a weird format - s1 = imgtool_get_info_string(imgclass, IMGTOOLINFO_STR_FILE_EXTENSIONS); - s2 = (char*)imgtool_library_malloc(strlen(s1) + 1); - strcpy(s2, s1); - module->extensions = s2; module->imgclass = *imgclass; - module->name = imgtool_library_strdup(imgtool_get_info_string(imgclass, IMGTOOLINFO_STR_NAME)); - module->description = imgtool_library_strdup(imgtool_get_info_string(imgclass, IMGTOOLINFO_STR_DESCRIPTION)); - module->eoln = imgtool_library_strdup_allow_null(imgtool_get_info_string(imgclass, IMGTOOLINFO_STR_EOLN)); - module->initial_path_separator = imgtool_get_info_int(imgclass, IMGTOOLINFO_INT_INITIAL_PATH_SEPARATOR) ? 1 : 0; - module->open_is_strict = imgtool_get_info_int(imgclass, IMGTOOLINFO_INT_OPEN_IS_STRICT) ? 1 : 0; - module->tracks_are_called_cylinders = imgtool_get_info_int(imgclass, IMGTOOLINFO_INT_TRACKS_ARE_CALLED_CYLINDERS) ? 1 : 0; - module->writing_untested = imgtool_get_info_int(imgclass, IMGTOOLINFO_INT_WRITING_UNTESTED) ? 1 : 0; - module->creation_untested = imgtool_get_info_int(imgclass, IMGTOOLINFO_INT_CREATION_UNTESTED) ? 1 : 0; - module->open = (imgtoolerr_t (*)(imgtool::image &, imgtool::stream::ptr &&)) imgtool_get_info_fct(imgclass, IMGTOOLINFO_PTR_OPEN); - module->create = (imgtoolerr_t (*)(imgtool::image &, imgtool::stream::ptr &&, util::option_resolution *)) imgtool_get_info_fct(imgclass, IMGTOOLINFO_PTR_CREATE); + module->name = imgtool_get_info_string(imgclass, IMGTOOLINFO_STR_NAME); + module->description = imgtool_get_info_string(imgclass, IMGTOOLINFO_STR_DESCRIPTION); + module->extensions = imgtool_get_info_string(imgclass, IMGTOOLINFO_STR_FILE_EXTENSIONS); + temp = imgtool_get_info_string(imgclass, IMGTOOLINFO_STR_EOLN); + module->eoln = (temp != nullptr) ? temp : ""; + module->initial_path_separator = imgtool_get_info_int(imgclass, IMGTOOLINFO_INT_INITIAL_PATH_SEPARATOR) ? true : false; + module->open_is_strict = imgtool_get_info_int(imgclass, IMGTOOLINFO_INT_OPEN_IS_STRICT) ? true : false; + module->tracks_are_called_cylinders = imgtool_get_info_int(imgclass, IMGTOOLINFO_INT_TRACKS_ARE_CALLED_CYLINDERS) ? true : false; + module->writing_untested = imgtool_get_info_int(imgclass, IMGTOOLINFO_INT_WRITING_UNTESTED) ? true : false; + module->creation_untested = imgtool_get_info_int(imgclass, IMGTOOLINFO_INT_CREATION_UNTESTED) ? true : false; + module->open = (imgtoolerr_t (*)(imgtool::image &, std::unique_ptr<imgtool::stream> &&)) imgtool_get_info_fct(imgclass, IMGTOOLINFO_PTR_OPEN); + module->create = (imgtoolerr_t (*)(imgtool::image &, std::unique_ptr<imgtool::stream> &&, util::option_resolution *)) imgtool_get_info_fct(imgclass, IMGTOOLINFO_PTR_CREATE); module->close = (void (*)(imgtool::image &)) imgtool_get_info_fct(imgclass, IMGTOOLINFO_PTR_CLOSE); module->info = (void (*)(imgtool::image &, std::ostream &)) imgtool_get_info_fct(imgclass, IMGTOOLINFO_PTR_INFO); module->read_sector = (imgtoolerr_t (*)(imgtool::image &, uint32_t, uint32_t, uint32_t, std::vector<uint8_t> &)) imgtool_get_info_fct(imgclass, IMGTOOLINFO_PTR_READ_SECTOR); @@ -201,7 +192,8 @@ void library::add_class(const imgtool_class *imgclass) module->list_partitions = (imgtoolerr_t (*)(imgtool::image &, std::vector<imgtool::partition_info> &)) imgtool_get_info_fct(imgclass, IMGTOOLINFO_PTR_LIST_PARTITIONS); module->block_size = imgtool_get_info_int(imgclass, IMGTOOLINFO_INT_BLOCK_SIZE); module->createimage_optguide = (const util::option_guide *) imgtool_get_info_ptr(imgclass, IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE); - module->createimage_optspec = imgtool_library_strdup_allow_null((const char*)imgtool_get_info_ptr(imgclass, IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC)); + temp = (char const *)imgtool_get_info_ptr(imgclass, IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC); + module->createimage_optspec = (temp != nullptr) ? temp : ""; module->image_extra_bytes += imgtool_get_info_int(imgclass, IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES); } @@ -269,7 +261,7 @@ int library::module_compare(const imgtool_module *m1, const imgtool_module *m2, switch(sort) { case sort_type::NAME: - rc = strcmp(m1->name, m2->name); + rc = strcmp(m1->name.c_str(), m2->name.c_str()); break; case sort_type::DESCRIPTION: rc = core_stricmp(m1->description, m2->description); @@ -319,34 +311,4 @@ const imgtool_module *library::findmodule(const std::string &module_name) } -//------------------------------------------------- -// imgtool_library_malloc -//------------------------------------------------- - -void *library::imgtool_library_malloc(size_t mem) -{ - return pool_malloc_lib(m_pool, mem); -} - - -//------------------------------------------------- -// imgtool_library_malloc -//------------------------------------------------- - -char *library::imgtool_library_strdup(const char *s) -{ - return pool_strdup_lib(m_pool, s); -} - - -//------------------------------------------------- -// imgtool_library_strdup_allow_null -//------------------------------------------------- - -char *library::imgtool_library_strdup_allow_null(const char *s) -{ - return s ? imgtool_library_strdup(s) : nullptr; -} - - } // namespace imgtool diff --git a/src/tools/imgtool/library.h b/src/tools/imgtool/library.h index c709a70201b..023b5fb948f 100644 --- a/src/tools/imgtool/library.h +++ b/src/tools/imgtool/library.h @@ -4,39 +4,44 @@ library.h - Code relevant to the Imgtool library; analogous to the MESS/MAME driver - list. + Code relevant to the Imgtool library; analogous to the MAME driver list. - Unlike MESS and MAME which have static driver lists, Imgtool has a - concept of a library and this library is built at startup time. + Unlike MAME which has a static driver lists, Imgtool has a concept of a + library and this library is built at startup time. dynamic for which modules are added to. This makes "dynamic" modules much easier ****************************************************************************/ +#ifndef MAME_TOOLS_IMGTOOL_LIBRARY_H +#define MAME_TOOLS_IMGTOOL_LIBRARY_H -#ifndef LIBRARY_H -#define LIBRARY_H +#pragma once -#include <time.h> -#include <list> -#include <chrono> +#include "imgterrs.h" -#include "corestr.h" -#include "opresolv.h" -#include "stream.h" -#include "unicode.h" -#include "charconv.h" -#include "pool.h" #include "timeconv.h" +#include "utilfwd.h" -namespace imgtool -{ - class image; - class partition; - class directory; -}; +#include <algorithm> +#include <chrono> +#include <cstdint> +#include <ctime> +#include <iosfwd> +#include <list> +#include <memory> +#include <string> +#include <vector> -enum imgtool_suggestion_viability_t + +namespace imgtool { + +class image; +class partition; +class directory; +class charconverter; +class stream; + +enum suggestion_viability_t { SUGGESTION_END, SUGGESTION_POSSIBLE, @@ -52,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 --- */ @@ -381,9 +395,9 @@ union imgtoolinfo void * f; /* generic function pointers */ char * s; /* generic strings */ - imgtoolerr_t (*open) (imgtool::image &image, imgtool::stream::ptr &&stream); + imgtoolerr_t (*open) (imgtool::image &image, std::unique_ptr<imgtool::stream> &&stream); void (*close) (imgtool::image &image); - imgtoolerr_t (*create) (imgtool::image &image, imgtool::stream::ptr &&stream, util::option_resolution *opts); + imgtoolerr_t (*create) (imgtool::image &image, std::unique_ptr<imgtool::stream> &&stream, util::option_resolution *opts); imgtoolerr_t (*create_partition) (imgtool::image &image, uint64_t first_block, uint64_t block_count); void (*info) (imgtool::image &image, std::ostream &stream); imgtoolerr_t (*begin_enum) (imgtool::directory &enumeration, const char *path); @@ -402,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); @@ -459,39 +473,39 @@ char *imgtool_temp_str(void); struct imgtool_module { - imgtool_class imgclass; + imgtool_class imgclass = { 0 }; - const char *name; - const char *description; - const char *extensions; - const char *eoln; + std::string name; + std::string description; + std::string extensions; + std::string eoln; - size_t image_extra_bytes; + size_t image_extra_bytes = 0; /* flags */ - unsigned int initial_path_separator : 1; - unsigned int open_is_strict : 1; - unsigned int tracks_are_called_cylinders : 1; /* used for hard drivers */ - unsigned int writing_untested : 1; /* used when we support writing, but not in main build */ - unsigned int creation_untested : 1; /* used when we support creation, but not in main build */ - - imgtoolerr_t (*open) (imgtool::image &image, imgtool::stream::ptr &&stream); - void (*close) (imgtool::image &image); - void (*info) (imgtool::image &image, std::ostream &stream); - imgtoolerr_t (*create) (imgtool::image &image, imgtool::stream::ptr &&stream, util::option_resolution *opts); - imgtoolerr_t (*get_geometry) (imgtool::image &image, uint32_t *track, 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); - imgtoolerr_t (*read_block) (imgtool::image &image, void *buffer, uint64_t block); - imgtoolerr_t (*write_block) (imgtool::image &image, const void *buffer, uint64_t block); - imgtoolerr_t (*list_partitions)(imgtool::image &image, std::vector<imgtool::partition_info> &partitions); - - uint32_t block_size; - - const util::option_guide *createimage_optguide; - const char *createimage_optspec; - - const void *extra; + bool initial_path_separator = false; + bool open_is_strict = false; + bool tracks_are_called_cylinders = false; /* used for hard drivers */ + bool writing_untested = false; /* used when we support writing, but not in main build */ + bool creation_untested = false; /* used when we support creation, but not in main build */ + + imgtoolerr_t (*open) (imgtool::image &image, std::unique_ptr<imgtool::stream> &&stream) = nullptr; + void (*close) (imgtool::image &image) = nullptr; + void (*info) (imgtool::image &image, std::ostream &stream) = nullptr; + imgtoolerr_t (*create) (imgtool::image &image, std::unique_ptr<imgtool::stream> &&stream, util::option_resolution *opts) = nullptr; + imgtoolerr_t (*get_geometry) (imgtool::image &image, uint32_t *track, uint32_t *heads, uint32_t *sectors) = nullptr; + imgtoolerr_t (*read_sector) (imgtool::image &image, uint32_t track, uint32_t head, uint32_t sector, std::vector<uint8_t> &buffer) = nullptr; + imgtoolerr_t (*write_sector) (imgtool::image &image, uint32_t track, uint32_t head, uint32_t sector, const void *buffer, size_t len) = nullptr; + imgtoolerr_t (*read_block) (imgtool::image &image, void *buffer, uint64_t block) = nullptr; + imgtoolerr_t (*write_block) (imgtool::image &image, const void *buffer, uint64_t block) = nullptr; + imgtoolerr_t (*list_partitions)(imgtool::image &image, std::vector<imgtool::partition_info> &partitions) = nullptr; + + uint32_t block_size = 0; + + const util::option_guide *createimage_optguide = nullptr; + std::string createimage_optspec; + + const void *extra = nullptr; }; namespace imgtool { @@ -531,7 +545,6 @@ public: const modulelist &modules() { return m_modules; } private: - object_pool * m_pool; modulelist m_modules; // internal lookup and iteration @@ -540,13 +553,8 @@ private: // helpers void add_class(const imgtool_class *imgclass); int module_compare(const imgtool_module *m1, const imgtool_module *m2, sort_type sort); - - // memory allocators for pooled library memory (these should go away in further C++-ification) - void *imgtool_library_malloc(size_t mem); - char *imgtool_library_strdup(const char *s); - char *imgtool_library_strdup_allow_null(const char *s); }; } // namespace imgtool -#endif // LIBRARY_H +#endif // MAME_TOOLS_IMGTOOL_LIBRARY_H diff --git a/src/tools/imgtool/main.cpp b/src/tools/imgtool/main.cpp index d5320beb347..ca38d7905cb 100644 --- a/src/tools/imgtool/main.cpp +++ b/src/tools/imgtool/main.cpp @@ -9,15 +9,23 @@ ***************************************************************************/ #include "imgtool.h" +#include "filter.h" #include "main.h" #include "modules.h" + +#include "corestr.h" +#include "opresolv.h" +#include "path.h" #include "strformat.h" +#include "unicode.h" + +#include "osdcore.h" // osd_get_command_line -#include <stdio.h> -#include <string.h> -#include <ctype.h> -#include <stdlib.h> -#include <time.h> +#include <cstdio> +#include <cstring> +#include <cctype> +#include <cstdlib> +#include <ctime> #include <iostream> #ifdef _WIN32 @@ -29,7 +37,7 @@ static void writeusage(std::wostream &output, bool write_word_usage, const struct command *c, char *argv[]) { - std::string cmdname = core_filename_extract_base(argv[0]); + std::string cmdname(core_filename_extract_base(argv[0])); util::stream_format(output, L"%s %s %s %s\n", @@ -43,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; @@ -97,7 +105,7 @@ static int parse_options(int argc, char *argv[], int minunnamed, int maxunnamed, if (*fork) goto optionalreadyspecified; - snprintf(buf, ARRAY_LENGTH(buf), "%s", value); + snprintf(buf, std::size(buf), "%s", value); *fork = buf; } else @@ -107,6 +115,9 @@ static int parse_options(int argc, char *argv[], int minunnamed, int maxunnamed, goto error; /* Too few unnamed */ util::option_resolution::entry *entry = resolution->find(name); + if (entry == nullptr) + goto error; /* Unknown option */ + if (entry->option_type() == util::option_guide::entry::option_type::ENUM_BEGIN) { const util::option_guide::entry *enum_value; @@ -231,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; @@ -248,7 +258,7 @@ static int cmd_dir(const struct command *c, int argc, char *argv[]) { std::string filesize_string = ent.directory ? "<DIR>" - : string_format("%u", (unsigned int) ent.filesize); + : util::string_format("%u", (unsigned int) ent.filesize); if (!ent.lastmodified_time.empty()) { @@ -266,16 +276,16 @@ static int cmd_dir(const struct command *c, int argc, char *argv[]) columnwidth_attributes, wstring_from_utf8(ent.attr), columnwidth_lastmodified, wstring_from_utf8(last_modified)); - if (ent.softlink && ent.softlink[0] != '\0') + if (ent.softlink[0] != '\0') util::stream_format(std::wcout, L"-> %s\n", wstring_from_utf8(ent.softlink)); - if (ent.comment && ent.comment[0] != '\0') + if (ent.comment[0] != '\0') util::stream_format(std::wcout, L": %s\n", wstring_from_utf8(ent.comment)); total_count++; total_size += ent.filesize; - memset(&ent, 0, sizeof(ent)); + ent = imgtool_dirent(); } freespace_err = partition->get_free_space(freespace); @@ -306,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; @@ -343,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; @@ -406,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)); @@ -430,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; @@ -458,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); @@ -564,7 +571,7 @@ static int cmd_identify(const struct command *c, int argc, char *argv[]) imgtoolerr_t err; int i; - err = imgtool::image::identify_file(argv[0], modules, ARRAY_LENGTH(modules)); + err = imgtool::image::identify_file(argv[0], modules, std::size(modules)); if (err) { reporterror(err, c, nullptr, argv[0], nullptr, nullptr, nullptr); @@ -597,7 +604,7 @@ static int cmd_create(const struct command *c, int argc, char *argv[]) goto error; } - if (module->createimage_optguide && module->createimage_optspec) + if (module->createimage_optguide && !module->createimage_optspec.empty()) { try { resolution.reset(new util::option_resolution(*module->createimage_optguide)); } catch (...) @@ -605,7 +612,7 @@ static int cmd_create(const struct command *c, int argc, char *argv[]) err = IMGTOOLERR_OUTOFMEMORY; goto error; } - resolution->set_specification(module->createimage_optspec); + resolution->set_specification(module->createimage_optspec.c_str()); } unnamedargs = parse_options(argc, argv, 2, 3, resolution.get(), nullptr, nullptr); @@ -748,7 +755,7 @@ static void listoptions(const util::option_guide &opt_guide, const char *opt_spe const util::option_resolution::entry &entry = *iter; std::stringstream description_buffer; - std::string opt_name = string_format("--%s", entry.identifier()); + std::string opt_name = util::string_format("--%s", entry.identifier()); const char *opt_desc = entry.display_name(); // is this option relevant? @@ -831,7 +838,7 @@ static int cmd_listdriveroptions(const struct command *c, int argc, char *argv[] if (opt_guide) { util::stream_format(std::wcout, L"Image specific creation options (usable on the 'create' command):\n\n"); - listoptions(*opt_guide, mod->createimage_optspec); + listoptions(*opt_guide, mod->createimage_optspec.c_str()); util::stream_format(std::wcout, L"\n"); } else @@ -873,7 +880,7 @@ int main(int argc, char *argv[]) int result; const struct command *c; const char *sample_format = "coco_jvc_rsdos"; - std::string cmdname = core_filename_extract_base(argv[0]); + std::string cmdname(core_filename_extract_base(argv[0])); #ifdef _WIN32 _setmode(_fileno(stdout), _O_U8TEXT); @@ -895,7 +902,7 @@ int main(int argc, char *argv[]) if (argc > 1) { /* figure out what command they are running, and run it */ - for (i = 0; i < ARRAY_LENGTH(cmds); i++) + for (i = 0; i < std::size(cmds); i++) { c = &cmds[i]; if (!core_stricmp(c->name, argv[1])) @@ -934,7 +941,7 @@ int main(int argc, char *argv[]) // Usage util::stream_format(std::wcerr, L"imgtool - Generic image manipulation tool for use with MAME\n\n"); - for (i = 0; i < ARRAY_LENGTH(cmds); i++) + for (i = 0; i < std::size(cmds); i++) { writeusage(std::wcerr, (i == 0), &cmds[i], argv); } diff --git a/src/tools/imgtool/modules.cpp b/src/tools/imgtool/modules.cpp index 1c573e3bcc9..fb443435a3b 100644 --- a/src/tools/imgtool/modules.cpp +++ b/src/tools/imgtool/modules.cpp @@ -8,7 +8,6 @@ ***************************************************************************/ -#include "imgtool.h" #include "modules.h" #ifndef MODULES_RECURSIVE @@ -29,8 +28,6 @@ static void (*const modules[])(const imgtool_class *imgclass, uint32_t state, un /* step 3: declare imgtool_create_canonical_library() */ imgtoolerr_t imgtool_create_canonical_library(bool omit_untested, std::unique_ptr<imgtool::library> &library) { - size_t i; - /* list of modules that we drop */ static const char *const irrelevant_modules[] = { @@ -42,14 +39,12 @@ imgtoolerr_t imgtool_create_canonical_library(bool omit_untested, std::unique_pt return IMGTOOLERR_OUTOFMEMORY; // create all modules - for (i = 0; i < ARRAY_LENGTH(modules); i++) - library->add(modules[i]); + for (auto &module : modules) + library->add(module); // remove irrelevant modules - for (i = 0; i < ARRAY_LENGTH(irrelevant_modules); i++) - { - library->unlink(irrelevant_modules[i]); - } + for (auto &module : irrelevant_modules) + library->unlink(module); // if we are omitting untested, go through and block out the functionality in question if (omit_untested) @@ -64,7 +59,7 @@ imgtoolerr_t imgtool_create_canonical_library(bool omit_untested, std::unique_pt { module->create = nullptr; module->createimage_optguide = nullptr; - module->createimage_optspec = nullptr; + module->createimage_optspec.clear(); } } } @@ -77,10 +72,9 @@ imgtoolerr_t imgtool_create_canonical_library(bool omit_untested, std::unique_pt MODULE(amiga_floppy) MODULE(concept) -MODULE(mac_mfs) -MODULE(mac_hfs) MODULE(hd) MODULE(rsdos) +MODULE(dgndos) MODULE(vzdos) MODULE(os9) MODULE(ti99_old) @@ -91,8 +85,6 @@ MODULE(ti99_ti99hd) MODULE(ti990) MODULE(pc_floppy) MODULE(pc_chd) -MODULE(prodos_525) -MODULE(prodos_35) MODULE(thom_fd_basic) MODULE(thom_qd_basic) MODULE(thom_sap_basic) diff --git a/src/tools/imgtool/modules/amiga.cpp b/src/tools/imgtool/modules/amiga.cpp index c1c5563012e..fcf1bd779a6 100644 --- a/src/tools/imgtool/modules/amiga.cpp +++ b/src/tools/imgtool/modules/amiga.cpp @@ -1,4 +1,4 @@ -// license:GPL-2.0+ +// license:BSD-3-Clause // copyright-holders:Dirk Best /**************************************************************************** @@ -13,14 +13,17 @@ Includes *****************************************************************************/ - -#include <time.h> -#include <string.h> -#include <ctype.h> - #include "imgtool.h" +#include "charconv.h" #include "iflopimg.h" -#include "formats/imageutl.h" + +#include "corestr.h" +#include "multibyte.h" +#include "opresolv.h" + +#include <cctype> +#include <cstring> +#include <ctime> @@ -252,15 +255,22 @@ static int intl_toupper(int c) /* Amiga filename case insensitive string compare */ -static int intl_stricmp(const char *s1, const char *s2) +static int intl_stricmp(std::string_view s1, std::string_view s2) { - for (;;) + auto s1_iter = s1.begin(); + auto s2_iter = s2.begin(); + while (true) { - int c1 = intl_toupper(*s1++); - int c2 = intl_toupper(*s2++); + if (s1.end() == s1_iter) + return (s2.end() == s2_iter) ? 0 : -1; + else if (s2.end() == s2_iter) + return 1; - if (c1 == 0 || c1 != c2) - return c1 - c2; + const int c1 = intl_toupper(uint8_t(*s1_iter++)); + const int c2 = intl_toupper(uint8_t(*s2_iter++)); + const int diff = c1 - c2; + if (diff) + return diff; } } @@ -388,7 +398,7 @@ static uint32_t block_checksum(uint8_t *buffer, int length) for (i = 0; i < length/4; i++) { - chksum += pick_integer_be(buffer, i*4, 4); + chksum += get_u32be(&buffer[i*4]); } return -chksum; @@ -464,7 +474,7 @@ static sec_type get_block_type(imgtool::image &img, int block) if (ret) return ST_INVALID; /* return type */ - switch ((int32_t) pick_integer_be(buffer, BSIZE-4, 4)) + switch (get_s32be(&buffer[BSIZE-4])) { case 1: return ST_ROOT; case 2: return ST_USERDIR; @@ -488,7 +498,7 @@ static imgtoolerr_t read_bitmap_block(imgtool::image &img, int block, bitmap_blo if (ret) return ret; /* fill in data */ - bm->chksum = pick_integer_be(buffer, 0, 4); + bm->chksum = get_u32be(&buffer[0]); copy_integer_array_be(bm->map, (uint32_t *) &buffer[4], MSIZE); return IMGTOOLERR_SUCCESS; @@ -502,7 +512,7 @@ static imgtoolerr_t write_bitmap_block(imgtool::image &img, int block, const bit uint8_t buffer[BSIZE]; /* Setup buffer */ - place_integer_be(buffer, 0, 4, bm->chksum); + put_u32be(&buffer[0], bm->chksum); copy_integer_array_be((uint32_t *) &buffer[4], bm->map, MSIZE); /* write block */ @@ -513,9 +523,8 @@ static imgtoolerr_t write_bitmap_block(imgtool::image &img, int block, const bit } -#ifdef UNUSED_FUNCTION /* Read a bitmap extended block */ -static imgtoolerr_t read_bitmap_ext_block(imgtool::image *img, int block, bitmap_ext_block *bm) +[[maybe_unused]] static imgtoolerr_t read_bitmap_ext_block(imgtool::image &img, int block, bitmap_ext_block *bm) { imgtoolerr_t ret; uint8_t buffer[BSIZE]; @@ -526,11 +535,10 @@ static imgtoolerr_t read_bitmap_ext_block(imgtool::image *img, int block, bitmap /* fill in data */ copy_integer_array_be(bm->map, (uint32_t *) &buffer, MSIZE); - bm->next = pick_integer_be(buffer, BSIZE-4, 4); + bm->next = get_u32be(&buffer[BSIZE-4]); return IMGTOOLERR_SUCCESS; } -#endif /* Read the root block */ @@ -546,17 +554,17 @@ static imgtoolerr_t read_root_block(imgtool::image &img, root_block *root) /* copy data to root_block */ memset(root, 0, sizeof(root_block)); - root->ht_size = pick_integer_be(buffer, 12, 4); - root->chksum = pick_integer_be(buffer, 20, 4); + root->ht_size = get_u32be(&buffer[12]); + root->chksum = get_u32be(&buffer[20]); copy_integer_array_be(root->ht, (uint32_t *) &buffer[24], TSIZE); - root->bm_flag = pick_integer_be(buffer, BSIZE-200, 4); + root->bm_flag = get_u32be(&buffer[BSIZE-200]); copy_integer_array_be(root->bm_pages, (uint32_t *) &buffer[BSIZE-196], 25); copy_date_be(&root->r, (uint32_t *) &buffer[BSIZE-92]); - root->name_len = pick_integer_be(buffer, BSIZE-80, 1); + root->name_len = buffer[BSIZE-80]; memcpy(root->diskname, &buffer[BSIZE-79], 30); copy_date_be(&root->v, (uint32_t *) &buffer[BSIZE-40]); copy_date_be(&root->c, (uint32_t *) &buffer[BSIZE-28]); - root->extension = pick_integer_be(buffer, BSIZE-8, 4); + root->extension = get_u32be(&buffer[BSIZE-8]); return IMGTOOLERR_SUCCESS; } @@ -570,25 +578,25 @@ static imgtoolerr_t write_root_block(imgtool::image &img, const root_block *root /* Setup buffer */ memset(buffer, 0, BSIZE); - place_integer_be(buffer, 0, 4, T_HEADER); - place_integer_be(buffer, 12, 4, root->ht_size); - place_integer_be(buffer, 20, 4, root->chksum); + put_u32be(&buffer[0], T_HEADER); + put_u32be(&buffer[12], root->ht_size); + put_u32be(&buffer[20], root->chksum); copy_integer_array_be((uint32_t *) &buffer[24], root->ht, TSIZE); - place_integer_be(buffer, BSIZE-200, 4, root->bm_flag); + put_u32be(&buffer[BSIZE-200], root->bm_flag); copy_integer_array_be((uint32_t *) &buffer[BSIZE-196], root->bm_pages, 25); - place_integer_be(buffer, BSIZE-92, 4, root->r.days); - place_integer_be(buffer, BSIZE-88, 4, root->r.mins); - place_integer_be(buffer, BSIZE-84, 4, root->r.ticks); - place_integer_be(buffer, BSIZE-80, 1, root->name_len); + put_u32be(&buffer[BSIZE-92], root->r.days); + put_u32be(&buffer[BSIZE-88], root->r.mins); + put_u32be(&buffer[BSIZE-84], root->r.ticks); + buffer[BSIZE-80] = root->name_len; memcpy(&buffer[BSIZE-79], root->diskname, root->name_len); - place_integer_be(buffer, BSIZE-40, 4, root->v.days); - place_integer_be(buffer, BSIZE-36, 4, root->v.mins); - place_integer_be(buffer, BSIZE-32, 4, root->v.ticks); - place_integer_be(buffer, BSIZE-28, 4, root->c.days); - place_integer_be(buffer, BSIZE-24, 4, root->c.mins); - place_integer_be(buffer, BSIZE-20, 4, root->c.ticks); - place_integer_be(buffer, BSIZE-8, 4, root->extension); - place_integer_be(buffer, BSIZE-4, 4, ST_ROOT); + put_u32be(&buffer[BSIZE-40], root->v.days); + put_u32be(&buffer[BSIZE-36], root->v.mins); + put_u32be(&buffer[BSIZE-32], root->v.ticks); + put_u32be(&buffer[BSIZE-28], root->c.days); + put_u32be(&buffer[BSIZE-24], root->c.mins); + put_u32be(&buffer[BSIZE-20], root->c.ticks); + put_u32be(&buffer[BSIZE-8], root->extension); + put_u32be(&buffer[BSIZE-4], ST_ROOT); /* write root block to image */ ret = write_block(img, get_total_blocks(img)/2, buffer); @@ -609,25 +617,25 @@ static imgtoolerr_t read_file_block(imgtool::image &img, int block, file_block * if (ret) return ret; /* fill in data */ - fb->header_key = pick_integer_be(buffer, 4, 4); - fb->high_seq = pick_integer_be(buffer, 8, 4); - fb->first_data = pick_integer_be(buffer, 16, 4); - fb->chksum = pick_integer_be(buffer, 20, 4); + fb->header_key = get_u32be(&buffer[4]); + fb->high_seq = get_u32be(&buffer[8]); + fb->first_data = get_u32be(&buffer[16]); + fb->chksum = get_u32be(&buffer[20]); copy_integer_array_be(fb->data_blocks, (uint32_t *) &buffer[24], TSIZE); - fb->uid = pick_integer_be(buffer, BSIZE-196, 2); - fb->gid = pick_integer_be(buffer, BSIZE-194, 2); - fb->protect = pick_integer_be(buffer, BSIZE-192, 4); - fb->byte_size = pick_integer_be(buffer, BSIZE-188, 4); - fb->comm_len = pick_integer_be(buffer, BSIZE-184, 1); + fb->uid = get_u16be(&buffer[BSIZE-196]); + fb->gid = get_u16be(&buffer[BSIZE-194]); + fb->protect = get_u32be(&buffer[BSIZE-192]); + fb->byte_size = get_u32be(&buffer[BSIZE-188]); + fb->comm_len = buffer[BSIZE-184]; memcpy(fb->comment, &buffer[BSIZE-183], 79); copy_date_be(&fb->date, (uint32_t *) &buffer[BSIZE-92]); - fb->name_len = pick_integer_be(buffer, BSIZE-80, 1); - memcpy(fb->filename, (uint32_t *) &buffer[BSIZE-79], 30); - fb->real_entry = pick_integer_be(buffer, BSIZE-44, 4); - fb->next_link = pick_integer_be(buffer, BSIZE-40, 4); - fb->hash_chain = pick_integer_be(buffer, BSIZE-16, 4); - fb->parent = pick_integer_be(buffer, BSIZE-12, 4); - fb->extension = pick_integer_be(buffer, BSIZE-8, 4); + fb->name_len = buffer[BSIZE-80]; + memcpy(fb->filename, &buffer[BSIZE-79], 30); + fb->real_entry = get_u32be(&buffer[BSIZE-44]); + fb->next_link = get_u32be(&buffer[BSIZE-40]); + fb->hash_chain = get_u32be(&buffer[BSIZE-16]); + fb->parent = get_u32be(&buffer[BSIZE-12]); + fb->extension = get_u32be(&buffer[BSIZE-8]); return IMGTOOLERR_SUCCESS; } @@ -643,12 +651,12 @@ static imgtoolerr_t read_file_ext_block(imgtool::image &img, int block, file_ext if (ret) return ret; /* fill in data */ - fe->header_key = pick_integer_be(buffer, 4, 4); - fe->high_seq = pick_integer_be(buffer, 8, 4); - fe->chksum = pick_integer_be(buffer, 20, 4); + fe->header_key = get_u32be(&buffer[4]); + fe->high_seq = get_u32be(&buffer[8]); + fe->chksum = get_u32be(&buffer[20]); copy_integer_array_be(fe->data_blocks, (uint32_t *) &buffer[24], TSIZE); - fe->parent = pick_integer_be(buffer, BSIZE-12, 4); - fe->extension = pick_integer_be(buffer, BSIZE-8, 4); + fe->parent = get_u32be(&buffer[BSIZE-12]); + fe->extension = get_u32be(&buffer[BSIZE-8]); return IMGTOOLERR_SUCCESS; } @@ -664,11 +672,11 @@ static imgtoolerr_t read_data_block(imgtool::image &img, int block, data_block * if (ret) return ret; /* fill in data */ - d->header_key = pick_integer_be(buffer, 4, 4); - d->seq_num = pick_integer_be(buffer, 8, 4); - d->data_size = pick_integer_be(buffer, 12, 4); - d->next_data = pick_integer_be(buffer, 16, 4); - d->chksum = pick_integer_be(buffer, 20, 4); + d->header_key = get_u32be(&buffer[4]); + d->seq_num = get_u32be(&buffer[8]); + d->data_size = get_u32be(&buffer[12]); + d->next_data = get_u32be(&buffer[16]); + d->chksum = get_u32be(&buffer[20]); memcpy(d->data, &buffer[24], BSIZE-24); return IMGTOOLERR_SUCCESS; @@ -686,21 +694,21 @@ static imgtoolerr_t read_dir_block(imgtool::image &img, int block, dir_block *db if (ret) return ret; /* fill in data */ - db->header_key = pick_integer_be(buffer, 4, 4); - db->chksum = pick_integer_be(buffer, 20, 4); + db->header_key = get_u32be(&buffer[4]); + db->chksum = get_u32be(&buffer[20]); copy_integer_array_be(db->ht, (uint32_t *) &buffer[24], TSIZE); - db->uid = pick_integer_be(buffer, BSIZE-196, 2); - db->gid = pick_integer_be(buffer, BSIZE-194, 2); - db->protect = pick_integer_be(buffer, BSIZE-192, 4); - db->comm_len = pick_integer_be(buffer, BSIZE-184, 1); + db->uid = get_u16be(&buffer[BSIZE-196]); + db->gid = get_u16be(&buffer[BSIZE-194]); + db->protect = get_u32be(&buffer[BSIZE-192]); + db->comm_len = buffer[BSIZE-184]; memcpy(db->comment, &buffer[BSIZE-183], 79); copy_date_be(&db->date, (uint32_t *) &buffer[BSIZE-92]); - db->name_len = pick_integer_be(buffer, BSIZE-80, 1); + db->name_len = buffer[BSIZE-80]; memcpy(db->dirname, (uint32_t *) &buffer[BSIZE-79], 30); - db->next_link = pick_integer_be(buffer, BSIZE-40, 4); - db->hash_chain = pick_integer_be(buffer, BSIZE-16, 4); - db->parent = pick_integer_be(buffer, BSIZE-12, 4); - db->extension = pick_integer_be(buffer, BSIZE-8, 4); + db->next_link = get_u32be(&buffer[BSIZE-40]); + db->hash_chain = get_u32be(&buffer[BSIZE-16]); + db->parent = get_u32be(&buffer[BSIZE-12]); + db->extension = get_u32be(&buffer[BSIZE-8]); return IMGTOOLERR_SUCCESS; } @@ -714,25 +722,25 @@ static imgtoolerr_t write_dir_block(imgtool::image &img, int block, const dir_bl memset(buffer, 0, BSIZE); /* Copy data */ - place_integer_be(buffer, 0, 4, T_HEADER); - place_integer_be(buffer, 4, 4, db->header_key); - place_integer_be(buffer, 20, 4, db->chksum); + put_u32be(&buffer[0], T_HEADER); + put_u32be(&buffer[4], db->header_key); + put_u32be(&buffer[20], db->chksum); copy_integer_array_be((uint32_t *) &buffer[24], db->ht, TSIZE); - place_integer_be(buffer, BSIZE-196, 2, db->uid); - place_integer_be(buffer, BSIZE-194, 2, db->gid); - place_integer_be(buffer, BSIZE-192, 4, db->protect); - place_integer_be(buffer, BSIZE-184, 1, db->comm_len); - memcpy((uint32_t *) &buffer[BSIZE-183], db->comment, db->comm_len); - place_integer_be(buffer, BSIZE-92, 4, db->date.days); - place_integer_be(buffer, BSIZE-88, 4, db->date.mins); - place_integer_be(buffer, BSIZE-84, 4, db->date.ticks); - place_integer_be(buffer, BSIZE-80, 1, db->name_len); - memcpy((uint32_t *) &buffer[BSIZE-79], db->dirname, db->name_len); - place_integer_be(buffer, BSIZE-40, 4, db->next_link); - place_integer_be(buffer, BSIZE-16, 4, db->hash_chain); - place_integer_be(buffer, BSIZE-12, 4, db->parent); - place_integer_be(buffer, BSIZE-8, 4, db->extension); - place_integer_be(buffer, BSIZE-4, 4, ST_USERDIR); + put_u16be(&buffer[BSIZE-196], db->uid); + put_u16be(&buffer[BSIZE-194], db->gid); + put_u32be(&buffer[BSIZE-192], db->protect); + buffer[BSIZE-184] = db->comm_len; + memcpy(&buffer[BSIZE-183], db->comment, db->comm_len); + put_u32be(&buffer[BSIZE-92], db->date.days); + put_u32be(&buffer[BSIZE-88], db->date.mins); + put_u32be(&buffer[BSIZE-84], db->date.ticks); + buffer[BSIZE-80] = db->name_len; + memcpy(&buffer[BSIZE-79], db->dirname, db->name_len); + put_u32be(&buffer[BSIZE-40], db->next_link); + put_u32be(&buffer[BSIZE-16], db->hash_chain); + put_u32be(&buffer[BSIZE-12], db->parent); + put_u32be(&buffer[BSIZE-8], db->extension); + put_u32be(&buffer[BSIZE-4], ST_USERDIR); /* Write block to disk */ return write_block(img, block, buffer); @@ -749,19 +757,19 @@ static imgtoolerr_t read_hardlink_block(imgtool::image &img, int block, hardlink if (ret) return ret; /* fill in data */ - hl->header_key = pick_integer_be(buffer, 4, 4); - hl->chksum = pick_integer_be(buffer, 20, 4); - hl->protect = pick_integer_be(buffer, BSIZE-192, 4); - hl->comm_len = pick_integer_be(buffer, BSIZE-184, 1); + hl->header_key = get_u32be(&buffer[4]); + hl->chksum = get_u32be(&buffer[20]); + hl->protect = get_u32be(&buffer[BSIZE-192]); + hl->comm_len = buffer[BSIZE-184]; memcpy(hl->comment, &buffer[BSIZE-183], 79); copy_date_be(&hl->date, (uint32_t *) &buffer[BSIZE-92]); - hl->name_len = pick_integer_be(buffer, BSIZE-80, 1); - memcpy(hl->hlname, (uint32_t *) &buffer[BSIZE-79], 30); - hl->real_entry = pick_integer_be(buffer, BSIZE-44, 4); - hl->next_link = pick_integer_be(buffer, BSIZE-40, 4); - hl->hash_chain = pick_integer_be(buffer, BSIZE-16, 4); - hl->parent = pick_integer_be(buffer, BSIZE-12, 4); - hl->sec_type = pick_integer_be(buffer, BSIZE-4, 4); + hl->name_len = buffer[BSIZE-80]; + memcpy(hl->hlname, &buffer[BSIZE-79], 30); + hl->real_entry = get_u32be(&buffer[BSIZE-44]); + hl->next_link = get_u32be(&buffer[BSIZE-40]); + hl->hash_chain = get_u32be(&buffer[BSIZE-16]); + hl->parent = get_u32be(&buffer[BSIZE-12]); + hl->sec_type = get_u32be(&buffer[BSIZE-4]); return IMGTOOLERR_SUCCESS; } @@ -777,17 +785,17 @@ static imgtoolerr_t read_softlink_block(imgtool::image &img, int block, softlink if (ret) return ret; /* fill in data */ - sl->header_key = pick_integer_be(buffer, 4, 4); - sl->chksum = pick_integer_be(buffer, 20, 4); + sl->header_key = get_u32be(&buffer[4]); + sl->chksum = get_u32be(&buffer[20]); memcpy(sl->symbolic_name, &buffer[24], BSIZE-224); - sl->protect = pick_integer_be(buffer, BSIZE-192, 4); - sl->comm_len = pick_integer_be(buffer, BSIZE-184, 1); + sl->protect = get_u32be(&buffer[BSIZE-192]); + sl->comm_len = buffer[BSIZE-184]; memcpy(sl->comment, &buffer[BSIZE-183], 79); copy_date_be(&sl->date, (uint32_t *) &buffer[BSIZE-92]); - sl->name_len = pick_integer_be(buffer, BSIZE-80, 1); - memcpy(sl->slname, (uint32_t *) &buffer[BSIZE-79], 30); - sl->hash_chain = pick_integer_be(buffer, BSIZE-16, 4); - sl->parent = pick_integer_be(buffer, BSIZE-12, 4); + sl->name_len = buffer[BSIZE-80]; + memcpy(sl->slname, &buffer[BSIZE-79], 30); + sl->hash_chain = get_u32be(&buffer[BSIZE-16]); + sl->parent = get_u32be(&buffer[BSIZE-12]); return IMGTOOLERR_SUCCESS; } @@ -837,16 +845,14 @@ static int is_intl(imgtool::image &img) t == DT_FFS_INTL_DIRC) ? true : false); } -#ifdef UNUSED_FUNCTION /* Returns true if the disk uses the directory cache mode */ -static int is_dirc(imgtool::image *img) +[[maybe_unused]] static int is_dirc(imgtool::image &img) { disk_type t = get_disk_type(img); return ((t == DT_OFS_INTL_DIRC || t == DT_FFS_INTL_DIRC) ? true : false); } -#endif static imgtoolerr_t get_hash_table(imgtool::image &img, int block, uint32_t *ht) { @@ -907,12 +913,10 @@ static imgtoolerr_t set_hash_table(imgtool::image &img, int block, const uint32_ return IMGTOOLERR_SUCCESS; } -#ifdef UNUSED_FUNCTION -static imgtoolerr_t get_root_hash_table(imgtool::image *img, uint32_t *ht) +[[maybe_unused]] static imgtoolerr_t get_root_hash_table(imgtool::image &img, uint32_t *ht) { return get_hash_table(img, get_total_blocks(img)/2, ht); } -#endif static imgtoolerr_t get_blockname(imgtool::image &img, int block, char *dest) { @@ -941,7 +945,7 @@ static imgtoolerr_t get_hash_chain(imgtool::image &img, int block, uint32_t *cha if (ret) return ret; /* Get chain value */ - *chain = pick_integer_be(buffer, BSIZE-16, 4); + *chain = get_u32be(&buffer[BSIZE-16]); return IMGTOOLERR_SUCCESS; } @@ -957,7 +961,7 @@ static imgtoolerr_t set_hash_chain(imgtool::image &img, int block, uint32_t chai if (ret) return ret; /* Copy new hash chain value into it */ - place_integer_be(buffer, BSIZE-16, 4, chain); + put_u32be(&buffer[BSIZE-16], chain); /* Write it back again */ ret = write_block(img, block, buffer); @@ -974,7 +978,7 @@ static imgtoolerr_t walk_hash_chain(imgtool::image &img, const char *path, int s char name[31]; /* choose compare function depending on intl mode */ - int (*cmp)(const char *, const char *) = is_intl(img) ? &intl_stricmp : &core_stricmp; + int (*cmp)(std::string_view, std::string_view) = is_intl(img) ? &intl_stricmp : &core_stricmp; /* initialize filenames */ memset(name, 0, sizeof(name)); @@ -1174,11 +1178,11 @@ static imgtoolerr_t fix_chksum(imgtool::image &img, int block, int bitmap) /* update checksum */ if (bitmap) { - place_integer_be(buffer, 0, 4, chksum); + put_u32be(&buffer[0], chksum); } else { - place_integer_be(buffer, 20, 4, chksum); + put_u32be(&buffer[20], chksum); } /* write back new block data */ @@ -1273,9 +1277,9 @@ static imgtoolerr_t update_block_modified_date(imgtool::image &img, int block) amiga_setup_time(now, &date); /* Write new time into block */ - place_integer_be(buffer, BSIZE-92, 4, date.days); - place_integer_be(buffer, BSIZE-88, 4, date.mins); - place_integer_be(buffer, BSIZE-84, 4, date.ticks); + put_u32be(&buffer[BSIZE-92], date.days); + put_u32be(&buffer[BSIZE-88], date.mins); + put_u32be(&buffer[BSIZE-84], date.ticks); /* Write block back to disk */ ret = write_block(img, block, buffer); @@ -1367,8 +1371,7 @@ static int get_first_bit(uint32_t *array, int size) } -#ifdef UNUSED_FUNCTION -static imgtoolerr_t walk_bitmap_ext_blocks(imgtool::image *img, int start, int *block) +[[maybe_unused]] static imgtoolerr_t walk_bitmap_ext_blocks(imgtool::image &img, int start, int *block) { imgtoolerr_t ret; bitmap_ext_block bm_ext; @@ -1400,7 +1403,6 @@ static imgtoolerr_t walk_bitmap_ext_blocks(imgtool::image *img, int start, int * /* else continue walking the list */ return walk_bitmap_ext_blocks(img, bm_ext.next, block); } -#endif /* Searches for a block marked as free @@ -1710,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); } @@ -1979,6 +1981,7 @@ static imgtoolerr_t amiga_image_nextenum(imgtool::directory &enumeration, imgtoo case ST_LINKDIR: ent.directory = 1; + [[fallthrough]]; case ST_LINKFILE: { @@ -2337,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; } @@ -2384,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 a1a3bdc203d..8c465032f28 100644 --- a/src/tools/imgtool/modules/bml3.cpp +++ b/src/tools/imgtool/modules/bml3.cpp @@ -18,12 +18,18 @@ - (used with MP-1802 floppy disk controller card) */ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> #include "imgtool.h" +#include "filter.h" #include "iflopimg.h" +#include "corestr.h" +#include "multibyte.h" +#include "opresolv.h" + +#include <cstdio> +#include <cstdlib> +#include <cstring> + #define MAX_SECTOR_SIZE 256 struct bml3_diskinfo @@ -129,7 +135,7 @@ static floperr_t get_bml3_dirent(imgtool::image &f, int index_loc, struct bml3_d ent->ftype = buf[11]; ent->asciiflag = buf[12]; ent->first_granule = buf[13]; - ent->lastsectorbytes = (buf[14] << 8) | buf[15]; + ent->lastsectorbytes = get_u16be(&buf[14]); break; default: return FLOPPY_ERROR_INVALIDIMAGE; @@ -162,8 +168,7 @@ static floperr_t put_bml3_dirent(imgtool::image &f, int index_loc, const struct buf[11] = ent->ftype; buf[12] = ent->asciiflag; buf[13] = ent->first_granule; - buf[14] = ent->lastsectorbytes >> 8; - buf[15] = ent->lastsectorbytes & 0xff; + put_u16be(&buf[14], ent->lastsectorbytes); break; default: return FLOPPY_ERROR_INVALIDIMAGE; @@ -512,7 +517,10 @@ static imgtoolerr_t bml3_diskimage_open(imgtool::image &image, imgtool::stream:: ferr = callbacks->get_sector_length(floppy, 0, 20, 1, §or_length); if (ferr) return imgtool_floppy_error(ferr); - int sectors_per_track = callbacks->get_sectors_per_track(floppy, 0, 20); + + int sectors_per_track = -1; + if (callbacks->get_sectors_per_track) + sectors_per_track = callbacks->get_sectors_per_track(floppy, 0, 20); if (heads_per_disk == 2 && sector_length == 128 && sectors_per_track == 16) { // single-sided, single-density @@ -604,8 +612,8 @@ eof: get_dirent_fname(fname, &rsent); - snprintf(ent.filename, ARRAY_LENGTH(ent.filename), "%s", fname); - snprintf(ent.attr, ARRAY_LENGTH(ent.attr), "%d %c", (int) rsent.ftype, (char) (rsent.asciiflag + 'B')); + snprintf(ent.filename, std::size(ent.filename), "%s", fname); + snprintf(ent.attr, std::size(ent.attr), "%d %c", (int) rsent.ftype, (char) (rsent.asciiflag + 'B')); } return IMGTOOLERR_SUCCESS; } @@ -832,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()); @@ -848,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; } @@ -903,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/concept.cpp b/src/tools/imgtool/modules/concept.cpp index 6bc0fe1bf22..da9689d455a 100644 --- a/src/tools/imgtool/modules/concept.cpp +++ b/src/tools/imgtool/modules/concept.cpp @@ -8,12 +8,15 @@ Raphael Nabet, 2003 */ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <limits.h> #include "imgtool.h" +#include "opresolv.h" + +#include <climits> +#include <cstdio> +#include <cstdlib> +#include <cstring> + struct UINT16xE { uint8_t bytes[2]; @@ -201,7 +204,6 @@ static int read_physical_record(imgtool::stream &file_handle, int secnum, void * return 0; } -#ifdef UNUSED_FUNCTION /* write_physical_record @@ -213,7 +215,7 @@ static int read_physical_record(imgtool::stream &file_handle, int secnum, void * Return non-zero on error */ -static int write_physical_record(imgtool::stream *file_handle, int secnum, const void *src) +[[maybe_unused]] static int write_physical_record(imgtool::stream *file_handle, int secnum, const void *src) { int reply; @@ -228,7 +230,6 @@ static int write_physical_record(imgtool::stream *file_handle, int secnum, const return 0; } -#endif /* Search for a file name on a concept_image @@ -357,8 +358,8 @@ static imgtoolerr_t concept_image_nextenum(imgtool::directory &enumeration, imgt int len = iter->image->dev_dir.file_dir[iter->index].filename[0]; const char *type; - if (len > ARRAY_LENGTH(ent.filename)) - len = ARRAY_LENGTH(ent.filename); + if (len > std::size(ent.filename)) + len = std::size(ent.filename); memcpy(ent.filename, iter->image->dev_dir.file_dir[iter->index].filename + 1, len); ent.filename[len] = 0; @@ -382,7 +383,7 @@ static imgtoolerr_t concept_image_nextenum(imgtool::directory &enumeration, imgt type = "???"; break; } - snprintf(ent.attr, ARRAY_LENGTH(ent.attr), "%s", type); + snprintf(ent.attr, std::size(ent.attr), "%s", type); /* len in physrecs */ ent.filesize = get_UINT16xE(iter->image->dev_dir.vol_hdr.disk_flipped, iter->image->dev_dir.file_dir[iter->index].next_block) diff --git a/src/tools/imgtool/modules/cybiko.cpp b/src/tools/imgtool/modules/cybiko.cpp index 1b9f43ee298..bfe9bfdddb2 100644 --- a/src/tools/imgtool/modules/cybiko.cpp +++ b/src/tools/imgtool/modules/cybiko.cpp @@ -10,6 +10,9 @@ #include "imgtool.h" +#include "multibyte.h" +#include "opresolv.h" + #include <zlib.h> struct cybiko_file_system @@ -52,8 +55,8 @@ enum }; #define BLOCK_USED(x) (x[0] & 0x80) -#define BLOCK_FILE_ID(x) buffer_read_16_be( x + 2) -#define BLOCK_PART_ID(x) buffer_read_16_be( x + 4) +#define BLOCK_FILE_ID(x) get_u16be( x + 2) +#define BLOCK_PART_ID(x) get_u16be( x + 4) #define BLOCK_FILENAME(x) (char*)(x + 7) #define FILE_HEADER_SIZE 0x48 @@ -79,30 +82,6 @@ uint32_t cybiko_time_setup(const imgtool::datetime &t) return cybiko_time_point.time_since_epoch().count(); } -static uint32_t buffer_read_32_be( uint8_t *buffer) -{ - return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3] << 0); -} - -static uint16_t buffer_read_16_be( uint8_t *buffer) -{ - return (buffer[0] << 8) | (buffer[1] << 0); -} - -static void buffer_write_32_be( uint8_t *buffer, uint32_t data) -{ - buffer[0] = (data >> 24) & 0xFF; - buffer[1] = (data >> 16) & 0xFF; - buffer[2] = (data >> 8) & 0xFF; - buffer[3] = (data >> 0) & 0xFF; -} - -static void buffer_write_16_be( uint8_t *buffer, uint16_t data) -{ - buffer[0] = (data >> 8) & 0xFF; - buffer[1] = (data >> 0) & 0xFF; -} - // page = crc1 (4) + wcnt (2) + crc2 (2) + data (x) + unk (2) static uint32_t page_buffer_calc_checksum_1( uint8_t *buffer, uint32_t size, int block_type) @@ -113,9 +92,9 @@ static uint32_t page_buffer_calc_checksum_1( uint8_t *buffer, uint32_t size, int static uint16_t page_buffer_calc_checksum_2( uint8_t *buffer) { uint16_t val = 0xAF17; - val ^= buffer_read_16_be( buffer + 0); - val ^= buffer_read_16_be( buffer + 2); - val ^= buffer_read_16_be( buffer + 4); + val ^= get_u16be( buffer + 0); + val ^= get_u16be( buffer + 2); + val ^= get_u16be( buffer + 4); return swapendian_int16(val); } @@ -124,11 +103,11 @@ static int page_buffer_verify( uint8_t *buffer, uint32_t size, int block_type) uint32_t checksum_page, checksum_calc; // checksum 1 checksum_calc = page_buffer_calc_checksum_1( buffer, size, block_type); - checksum_page = buffer_read_32_be( buffer + 0); + checksum_page = get_u32be( buffer + 0); if (checksum_calc != checksum_page) return false; // checksum 2 checksum_calc = page_buffer_calc_checksum_2( buffer); - checksum_page = buffer_read_16_be( buffer + 6); + checksum_page = get_u16be( buffer + 6); if (checksum_calc != checksum_page) return false; // ok return true; @@ -198,10 +177,10 @@ static int cfs_block_write( cybiko_file_system *cfs, uint8_t *buffer, int block_ uint8_t buffer_page[MAX_PAGE_SIZE]; uint32_t page; memcpy( buffer_page + 8, buffer, cfs->page_size - 10); - buffer_write_32_be( buffer_page + 0, page_buffer_calc_checksum_1( buffer_page, cfs->page_size, block_type)); - buffer_write_16_be( buffer_page + 4, cfs->write_count++); - buffer_write_16_be( buffer_page + 6, page_buffer_calc_checksum_2( buffer_page)); - buffer_write_16_be( buffer_page + cfs->page_size - 2, 0xFFFF); + put_u32be( buffer_page + 0, page_buffer_calc_checksum_1( buffer_page, cfs->page_size, block_type)); + put_u16be( buffer_page + 4, cfs->write_count++); + put_u16be( buffer_page + 6, page_buffer_calc_checksum_2( buffer_page)); + put_u16be( buffer_page + cfs->page_size - 2, 0xFFFF); if (!cfs_block_to_page( cfs, block_type, block, &page)) return false; if (!cfs_page_write( cfs, buffer_page, page)) return false; return true; @@ -236,7 +215,7 @@ static int cfs_file_info( cybiko_file_system *cfs, uint16_t file_id, cfs_file *f if (BLOCK_PART_ID(buffer) == 0) { strcpy( file->name, BLOCK_FILENAME(buffer)); - file->date = buffer_read_32_be( buffer + 6 + FILE_HEADER_SIZE - 4); + file->date = get_u32be( buffer + 6 + FILE_HEADER_SIZE - 4); } file->size += buffer[1]; file->blocks++; @@ -499,13 +478,13 @@ static imgtoolerr_t cybiko_image_write_file(imgtool::partition &partition, const buffer[0] = 0x80; buffer[1] = cfs->page_size - 0x10 - ((part_id == 0) ? FILE_HEADER_SIZE : 0); if (bytes_left < buffer[1]) buffer[1] = bytes_left; - buffer_write_16_be( buffer + 2, file_id); - buffer_write_16_be( buffer + 4, part_id); + put_u16be( buffer + 2, file_id); + put_u16be( buffer + 4, part_id); if (part_id == 0) { buffer[6] = 0; strcpy(BLOCK_FILENAME(buffer), filename); - buffer_write_32_be(buffer + 6 + FILE_HEADER_SIZE - 4, cybiko_time_setup(imgtool::datetime::now(imgtool::datetime::datetime_type::LOCAL))); + put_u32be(buffer + 6 + FILE_HEADER_SIZE - 4, cybiko_time_setup(imgtool::datetime::now(imgtool::datetime::datetime_type::LOCAL))); sourcef.read(buffer + 6 + FILE_HEADER_SIZE, buffer[1]); } else diff --git a/src/tools/imgtool/modules/cybikoxt.cpp b/src/tools/imgtool/modules/cybikoxt.cpp index 8c2980de449..556f37fde76 100644 --- a/src/tools/imgtool/modules/cybikoxt.cpp +++ b/src/tools/imgtool/modules/cybikoxt.cpp @@ -10,6 +10,8 @@ #include "imgtool.h" +#include "multibyte.h" + #include <zlib.h> struct cybiko_file_system @@ -44,8 +46,8 @@ enum #define INVALID_FILE_ID 0xFFFF #define BLOCK_USED(x) (x[0] & 0x80) -#define BLOCK_FILE_ID(x) buffer_read_16_be( x + 2) -#define BLOCK_PART_ID(x) buffer_read_16_be( x + 4) +#define BLOCK_FILE_ID(x) get_u16be( x + 2) +#define BLOCK_PART_ID(x) get_u16be( x + 4) #define BLOCK_FILENAME(x) (char*)(x + 7) #define FILE_HEADER_SIZE 0x48 @@ -58,30 +60,6 @@ static cybiko_file_system *get_cfs(imgtool::image &image) extern imgtool::datetime cybiko_time_crack(uint32_t cfs_time); extern uint32_t cybiko_time_setup(const imgtool::datetime &t); -static uint32_t buffer_read_32_be( uint8_t *buffer) -{ - return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3] << 0); -} - -static uint16_t buffer_read_16_be( uint8_t *buffer) -{ - return (buffer[0] << 8) | (buffer[1] << 0); -} - -static void buffer_write_32_be( uint8_t *buffer, uint32_t data) -{ - buffer[0] = (data >> 24) & 0xFF; - buffer[1] = (data >> 16) & 0xFF; - buffer[2] = (data >> 8) & 0xFF; - buffer[3] = (data >> 0) & 0xFF; -} - -static void buffer_write_16_be( uint8_t *buffer, uint16_t data) -{ - buffer[0] = (data >> 8) & 0xFF; - buffer[1] = (data >> 0) & 0xFF; -} - // page = crc (2) + data (x) static uint16_t page_buffer_calc_checksum( uint8_t *data, uint32_t size) @@ -103,7 +81,7 @@ static int page_buffer_verify( uint8_t *buffer, uint32_t size, int block_type) { uint32_t checksum_page, checksum_calc; checksum_calc = page_buffer_calc_checksum( buffer + 2, size - 2); - checksum_page = buffer_read_16_be( buffer + 0); + checksum_page = get_u16be( buffer + 0); if (checksum_calc != checksum_page) return false; } // ok @@ -183,7 +161,7 @@ static int cfs_block_write( cybiko_file_system *cfs, uint8_t *buffer, int block_ { checksum = page_buffer_calc_checksum( buffer_page + 2, cfs->page_size - 2); } - buffer_write_16_be( buffer_page + 0, checksum); + put_u16be( buffer_page + 0, checksum); if (!cfs_block_to_page( cfs, block_type, block, &page)) return false; if (!cfs_page_write( cfs, buffer_page, page)) return false; return true; @@ -218,7 +196,7 @@ static int cfs_file_info( cybiko_file_system *cfs, uint16_t file_id, cfs_file *f if (BLOCK_PART_ID(buffer) == 0) { strcpy( file->name, BLOCK_FILENAME(buffer)); - file->date = buffer_read_32_be( buffer + 6 + FILE_HEADER_SIZE - 4); + file->date = get_u32be( buffer + 6 + FILE_HEADER_SIZE - 4); } file->size += buffer[1]; file->blocks++; @@ -460,13 +438,13 @@ static imgtoolerr_t cybiko_image_write_file(imgtool::partition &partition, const buffer[0] = 0x80; buffer[1] = (cfs->page_size - 2) - 6 - ((part_id == 0) ? FILE_HEADER_SIZE : 0); if (bytes_left < buffer[1]) buffer[1] = bytes_left; - buffer_write_16_be( buffer + 2, file_id); - buffer_write_16_be( buffer + 4, part_id); + put_u16be( buffer + 2, file_id); + put_u16be( buffer + 4, part_id); if (part_id == 0) { buffer[6] = 0x20; strcpy(BLOCK_FILENAME(buffer), filename); - buffer_write_32_be( buffer + 6 + FILE_HEADER_SIZE - 4, cybiko_time_setup(imgtool::datetime::now(imgtool::datetime::datetime_type::LOCAL))); + put_u32be( buffer + 6 + FILE_HEADER_SIZE - 4, cybiko_time_setup(imgtool::datetime::now(imgtool::datetime::datetime_type::LOCAL))); sourcef.read(buffer + 6 + FILE_HEADER_SIZE, buffer[1]); } else diff --git a/src/tools/imgtool/modules/dgndos.cpp b/src/tools/imgtool/modules/dgndos.cpp new file mode 100644 index 00000000000..692c010d057 --- /dev/null +++ b/src/tools/imgtool/modules/dgndos.cpp @@ -0,0 +1,1256 @@ +// license:BSD-3-Clause +// copyright-holders:tim lindner +/**************************************************************************** + + dgndos.cpp + + Dragon DOS disk images + + I am not happy with the sector allocation algorithm + +****************************************************************************/ + +#include "imgtool.h" +#include "filter.h" +#include "iflopimg.h" + +#include "formats/coco_dsk.h" +#include "corestr.h" +#include "opresolv.h" + +#include <cstdio> +#include <cstdlib> +#include <cstring> + +#ifdef _MSC_VER +#pragma pack(push,1) +#define A_PACKED +#else +#define A_PACKED __attribute__((packed)) +#endif + +typedef struct A_PACKED dngdos_sector_allocation_format { + uint16_t lsn; + uint8_t count; +} dngdos_sector_allocation_format; + +typedef struct A_PACKED dngdos_file_header_block { + char filename[11]; + dngdos_sector_allocation_format block[4]; +} dngdos_file_header_block; + +typedef struct A_PACKED dngdos_file_continuation_block { + dngdos_sector_allocation_format block[7]; + uint16_t unused; +} dngdos_file_continuation_block; + +struct A_PACKED dgndos_dirent +{ + unsigned char flag_byte; + union block { + dngdos_file_header_block header; + dngdos_file_continuation_block continuation; + } block; + uint8_t dngdos_last_or_next; +}; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif + +struct dgndos_direnum +{ + int index; + bool eof; +}; + +/********************************************************************* + Imgtool module code +*********************************************************************/ + +#define DGNDOS_OPTIONS_PROTECT 'P' +#define MAX_DIRENTS 160 +#define HEADER_EXTENTS_COUNT 4 +#define CONT_EXTENTS_COUNT 7 + +#define DGNDOS_DELETED_BIT 0x80 // deleted entry +#define DGNDOS_CONTINUED_BIT 0x20 // byte at offset 0x18 give next entry number +#define DGNDOS_END_BIT 0x08 // end of directory +#define DGNDOS_PROTECT_BIT 0x02 // ignored +#define DGNDOS_CONTINUATION_BIT 0x01 // this is a continuation block + +static imgtoolerr_t get_dgndos_dirent(uint8_t *track, int index_loc, dgndos_dirent &ent) +{ + if (index_loc >= MAX_DIRENTS) + return IMGTOOLERR_FILENOTFOUND; + + int sector = 3 + (index_loc / 10); + int offset = (index_loc * 25) % 250; + + memcpy( (void *)&ent, track + (256 * (sector-1)) + offset, sizeof(ent)); + + return IMGTOOLERR_SUCCESS; +} + +static imgtoolerr_t put_dgndos_dirent(uint8_t *track, int index_loc, const dgndos_dirent &ent) +{ + if (index_loc >= MAX_DIRENTS) + return IMGTOOLERR_FILENOTFOUND; + + int sector = 3 + (index_loc / 10); + int offset = (index_loc * 25) % 250; + + memcpy( track + (256 * (sector-1)) + offset, (void *)&ent, sizeof(ent)); + + return IMGTOOLERR_SUCCESS; +} + +static std::string get_dirent_fname(const dgndos_dirent &ent) +{ + return extract_padded_filename(ent.block.header.filename, 8, 3, '\0'); +} + +static bool dgndos_real_file( dgndos_dirent &ent ) +{ + if( ent.flag_byte & DGNDOS_DELETED_BIT) return false; + if( ent.flag_byte & DGNDOS_CONTINUATION_BIT) return false; + + return true; +} + +static imgtoolerr_t lookup_dgndos_file(uint8_t *entire_track, const char *fname, dgndos_dirent &ent, int *position = nullptr) +{ + int i = 0; + imgtoolerr_t err; + std::string fnamebuf; + + do + { + do + { + err = get_dgndos_dirent( entire_track, i++, ent ); + if( err ) return err; + + if( ent.flag_byte & DGNDOS_END_BIT ) return IMGTOOLERR_FILENOTFOUND; + } + while( ! dgndos_real_file(ent) ); + + fnamebuf = get_dirent_fname(ent); + } + while(core_stricmp(fnamebuf, fname)); + + if (position) + *position = i - 1; + + return IMGTOOLERR_SUCCESS; +} + +static imgtoolerr_t dgndos_get_geometry(uint8_t *entire_track, int *bitmap_count, int *heads, int *tracks_on_disk, int *sectors_per_track) +{ + unsigned int tod, spt, sides; + + tod = entire_track[0xfc]; + spt = entire_track[0xfd]; + + if( (~tod & 0xff) != entire_track[0xfe]) + { +// fprintf( stderr, "tracks_on_disk check failed: %u == %u\n", (~tod & 0xff), entire_track[0xfe] ); + return IMGTOOLERR_CORRUPTIMAGE; + } + + if( (~spt & 0xff) != entire_track[0xff]) + { +// fprintf( stderr, "sectors_per_track check failed: %u == %u\n", (~spt & 0xff), entire_track[0xff] ); + return IMGTOOLERR_CORRUPTIMAGE; + } + + if(spt == 36) + { + sides = 1; + } + else if(spt == 18 ) + { + sides = 0; + } + else + { +// fprintf( stderr, "sides check failed\n" ); + return IMGTOOLERR_CORRUPTIMAGE; + } + + if( heads ) *heads = sides; + if( tracks_on_disk) *tracks_on_disk = tod; + if( sectors_per_track ) *sectors_per_track = spt; + if( bitmap_count ) *bitmap_count = (tod * sides * 18) + (tod * 18); + + return IMGTOOLERR_SUCCESS; +} + +static imgtoolerr_t dgndos_convert_lsn(uint8_t *entire_track, int lsn, int *head, int *track, int *sector ) +{ + int tracks_on_disk; + int sectors_per_track; + int sides; + + imgtoolerr_t err = dgndos_get_geometry(entire_track, nullptr, &sides, &tracks_on_disk, §ors_per_track); + if(err) return err; + + if( sides == 0 ) + { + *head = 0; + *track = lsn / 18; + *sector = (lsn % 18) + 1; + } + else + { + *head = (lsn / 18) % 2; + *track = lsn / 36; + *sector = (lsn % 18) + 1; + } + + return IMGTOOLERR_SUCCESS; +} + +#define ALLOCATE_BIT 1 +#define QUERY_BIT 0 +#define DEALLOCATE_BIT -1 + +static int dgndos_set_reset_bitmap( uint8_t *entire_track, int lsn, int set ) +{ + int startbyte = lsn / 8; + int startbit = lsn % 8; + + if( lsn > 1439 ) startbyte += 76; + + if(set > QUERY_BIT) // ALLOCATE_BIT + { + // 0 = used, 1 = free + entire_track[startbyte] &= ~(1 << startbit); + } + else if( set < QUERY_BIT ) // DEALLOCATE_BIT + { + // 0 = used, 1 = free + entire_track[startbyte] |= (1 << startbit); + } + + // 0 = used, 1 = free + return (entire_track[startbyte] & (1 << startbit)) != 0; +} + +static int dgndos_is_sector_avaiable(uint8_t *entire_track, int lsn) +{ + return dgndos_set_reset_bitmap( entire_track, lsn, QUERY_BIT ); +} + +static int dgndos_fat_allocate_sector(uint8_t *entire_track, int lsn) +{ + return dgndos_set_reset_bitmap( entire_track, lsn, ALLOCATE_BIT ); +} + +static int dgndos_fat_deallocate_sector(uint8_t *entire_track, int lsn) +{ + return dgndos_set_reset_bitmap( entire_track, lsn, DEALLOCATE_BIT ); +} + +static int dgndos_fat_deallocate_span(uint8_t *entire_track, int lsn, int count) +{ + int value = 0; + + for( int i=lsn; i<lsn+count; i++) + { + value = dgndos_fat_deallocate_sector(entire_track, i); + } + + return value; +} + +static imgtoolerr_t dgndos_get_avaiable_dirent_position(uint8_t *entire_track, int *position ) +{ + int i; + imgtoolerr_t err; + dgndos_dirent ent; + + for( i=0; i<MAX_DIRENTS; i++ ) + { + err = get_dgndos_dirent(entire_track, i, ent); + if( err ) return err; + + if( ent.flag_byte & DGNDOS_DELETED_BIT) break; + + if( ent.flag_byte & DGNDOS_END_BIT) break; + } + + if( i == MAX_DIRENTS ) + { + return IMGTOOLERR_NOSPACE; + } + + if( position ) *position = i; + + return IMGTOOLERR_SUCCESS; +} + +static imgtoolerr_t dgndos_get_avaiable_dirent(uint8_t *entire_track, dgndos_dirent &ent, int *position ) +{ + int i; + imgtoolerr_t err; + + for( i=0; i<MAX_DIRENTS; i++ ) + { + err = get_dgndos_dirent(entire_track, i, ent); + if( err ) return err; + + if( ent.flag_byte & DGNDOS_DELETED_BIT) break; + + if( ent.flag_byte & DGNDOS_END_BIT) break; + } + + if( i == MAX_DIRENTS ) + { + return IMGTOOLERR_NOSPACE; + } + + if( position ) *position = i; + + return IMGTOOLERR_SUCCESS; +} + +static imgtoolerr_t dgndos_get_avaiable_sector( uint8_t *entire_track, int *lsn ) +{ + int bitmap_count, i; + int pos_diff = 18; + int neg_diff = 36; + int start = 360; + + imgtoolerr_t err = dgndos_get_geometry(entire_track, &bitmap_count, nullptr, nullptr, nullptr); + if(err) return err; + + do + { + i = start; + while ( i >= 0 ) + { + if( dgndos_is_sector_avaiable(entire_track, i) ) + { + *lsn = i; + return IMGTOOLERR_SUCCESS; + } + + i -= neg_diff; + } + + i = start; + while( i < bitmap_count ) + { + if( dgndos_is_sector_avaiable(entire_track, i) ) + { + *lsn = i; + return IMGTOOLERR_SUCCESS; + } + + i += pos_diff; + } + + start--; + } + while( start >= 335 ); + + return IMGTOOLERR_NOSPACE; +} + +static imgtoolerr_t dgndos_count_dirents(uint8_t *entire_track, dgndos_dirent dgnent, int *result) +{ + imgtoolerr_t err = IMGTOOLERR_SUCCESS; + *result = 1; + + while( (dgnent.flag_byte & DGNDOS_CONTINUED_BIT) && *result < MAX_DIRENTS ) + { + (*result)++; + err = get_dgndos_dirent(entire_track, dgnent.dngdos_last_or_next, dgnent); + } + + return err; +} + +static imgtoolerr_t dgndos_get_file_size(uint8_t *entire_track, dgndos_dirent dgnent, size_t &filesize) +{ + imgtoolerr_t err; + int directory_entry_count = 0; + int extent = 0; + int block_size; + int done; + int count; + int i; + + filesize = 0; + + do + { + if(directory_entry_count>MAX_DIRENTS) return IMGTOOLERR_CORRUPTDIR; + + count = dgnent.flag_byte & DGNDOS_CONTINUATION_BIT ? dgnent.block.continuation.block[extent].count : dgnent.block.header.block[extent].count; + + if( count == 0 ) break; + + i = 0; + + // count extents except last sector + while (i < count - 1) + { + filesize += 256; + i++; + } + + block_size = 256; + done = false; + + if( extent < (dgnent.flag_byte & DGNDOS_CONTINUATION_BIT ? CONT_EXTENTS_COUNT : HEADER_EXTENTS_COUNT) - 1 ) + { + if( (dgnent.flag_byte & DGNDOS_CONTINUATION_BIT ? dgnent.block.continuation.block[extent+1].count : dgnent.block.header.block[extent+1].count) == 0 ) + { + // not last extent, and yes continuation + if( dgnent.dngdos_last_or_next == 0 ) + block_size = 256; + else + block_size = dgnent.dngdos_last_or_next; + + done = true; + } + } + else if( extent == (dgnent.flag_byte & DGNDOS_CONTINUATION_BIT ? CONT_EXTENTS_COUNT : HEADER_EXTENTS_COUNT) - 1) + { + if( !(dgnent.flag_byte & DGNDOS_CONTINUED_BIT) ) + { + // is last extent, and no continuation + if( dgnent.dngdos_last_or_next == 0 ) + block_size = 256; + else + block_size = dgnent.dngdos_last_or_next; + + done = true; + } + } + + filesize += block_size; + + extent++; + + if( extent == (dgnent.flag_byte & DGNDOS_CONTINUATION_BIT ? CONT_EXTENTS_COUNT : HEADER_EXTENTS_COUNT) ) + { + if( dgnent.flag_byte & DGNDOS_CONTINUED_BIT) + { + err = get_dgndos_dirent(entire_track, dgnent.dngdos_last_or_next, *(&dgnent) ); + if(err) return err; + + extent = 0; + directory_entry_count++; + } + } + } + while( !done ); + + return IMGTOOLERR_SUCCESS; +} + +static floperr_t dgndos_get_directory_track( imgtool::image &image, int track, uint8_t *buffer ) +{ + floperr_t ferr; + + for(int i=1; i<=18; i++ ) + { + ferr = floppy_read_sector(imgtool_floppy(image), 0, track, i, 0, &(buffer[(i-1)*256]), 256); + if(ferr) break; + } + + return ferr; +} + +static floperr_t dgndos_put_directory_track( imgtool::image &image, int track, uint8_t *buffer ) +{ + floperr_t ferr; + + for(int i=1; i<=18; i++ ) + { + ferr = floppy_write_sector(imgtool_floppy(image), 0, track, i, 0, &(buffer[(i-1)*256]), 256, 0); + if(ferr) break; + } + + return ferr; +} + +static imgtoolerr_t dgndos_diskimage_nextenum(imgtool::directory &enumeration, imgtool_dirent &ent) +{ + floperr_t ferr; + imgtoolerr_t err; + size_t filesize; + dgndos_direnum *dgnenum; + dgndos_dirent dgnent; + int dir_ent_count; + + imgtool::image &image(enumeration.image()); + + uint8_t entire_track20[18*256]; + + ferr = dgndos_get_directory_track( image, 20, entire_track20 ); + if (ferr) return imgtool_floppy_error(ferr); + + dgnenum = (dgndos_direnum *) enumeration.extra_bytes(); + + /* Did we hit the end of file before? */ + if (dgnenum->eof) return IMGTOOLERR_SUCCESS; + + do + { + if (dgnenum->index >= MAX_DIRENTS) + { + dgnenum->eof = 1; + ent.eof = 1; + return IMGTOOLERR_SUCCESS; + } + + err = get_dgndos_dirent(entire_track20, dgnenum->index++, dgnent); + if (err) return err; + + if( dgndos_real_file( dgnent ) ) break; + } + while( ! (dgnent.flag_byte & DGNDOS_END_BIT) ); + + // now are we at the eof point? + if (dgnent.flag_byte & DGNDOS_END_BIT) + { + dgnenum->eof = 1; + ent.eof = 1; + } + else + { + err = dgndos_get_file_size(entire_track20, dgnent, filesize); + if (err) return err; + + if (filesize == ((size_t) -1)) + { + /* corrupt! */ + ent.filesize = 0; + ent.corrupt = 1; + } + else + { + ent.filesize = filesize; + ent.corrupt = 0; + } + ent.eof = 0; + + std::string fname = get_dirent_fname(dgnent); + + err = dgndos_count_dirents(entire_track20, dgnent, &dir_ent_count); + if (err) return err; + + snprintf(ent.filename, std::size(ent.filename), "%s", fname.c_str()); + snprintf(ent.attr, std::size(ent.attr), "%c (%03d)", + (char) (dgnent.flag_byte & DGNDOS_PROTECT_BIT ? 'P' : '.'), + dir_ent_count); + } + + return IMGTOOLERR_SUCCESS; +} + +static imgtoolerr_t dgndos_diskimage_freespace(imgtool::partition &partition, uint64_t *size) +{ + floperr_t ferr; + imgtool::image &image(partition.image()); + int bitmap_count(0); + + uint8_t entire_track20[18*256]; + + ferr = dgndos_get_directory_track( image, 20, entire_track20 ); + if (ferr) return imgtool_floppy_error(ferr); + + *size = 0; + + dgndos_get_geometry(entire_track20, &bitmap_count, nullptr, nullptr, nullptr); + + for( int i=0; i<bitmap_count; i++ ) + { + if (dgndos_is_sector_avaiable(entire_track20, i)) + { + *size += 256; + } + } + + return IMGTOOLERR_SUCCESS; +} + +static imgtoolerr_t dgndos_diskimage_readfile(imgtool::partition &partition, const char *fname, const char *fork, imgtool::stream &destf) +{ + floperr_t ferr; + imgtoolerr_t err; + dgndos_dirent ent; + imgtool::image &image(partition.image()); + int directory_entry_count = 0; + int head, track, sector; + int position; + int extent = 0; + int block_size; + int done; + int lsn; + int count; + int i; + + uint8_t entire_track20[18*256]; + + ferr = dgndos_get_directory_track( image, 20, entire_track20 ); + if (ferr) return imgtool_floppy_error(ferr); + + err = lookup_dgndos_file(entire_track20, fname, ent, &position); + if (err) return err; + + do + { + if(directory_entry_count>MAX_DIRENTS) return IMGTOOLERR_CORRUPTDIR; + + lsn = big_endianize_int16( ent.flag_byte & DGNDOS_CONTINUATION_BIT ? ent.block.continuation.block[extent].lsn : ent.block.header.block[extent].lsn ); + count = ent.flag_byte & DGNDOS_CONTINUATION_BIT ? ent.block.continuation.block[extent].count : ent.block.header.block[extent].count; + + if( count == 0 ) break; + + i = 0; + + // get extents except last sector + while (i < count - 1) + { + err = dgndos_convert_lsn(entire_track20, lsn + i, &head, &track, §or ); + if(err) return err; + + err = imgtool_floppy_read_sector_to_stream(image, head, track, sector, 0, 256, destf); + if (err) return err; + + i++; + } + + block_size = 256; + done = false; + + if( extent < (ent.flag_byte & DGNDOS_CONTINUATION_BIT ? CONT_EXTENTS_COUNT : HEADER_EXTENTS_COUNT) - 1 ) + { + if( (ent.flag_byte & DGNDOS_CONTINUATION_BIT ? ent.block.continuation.block[extent+1].count : ent.block.header.block[extent+1].count) == 0 ) + { + // not last extent, and yes continuation + if( ent.dngdos_last_or_next == 0 ) + block_size = 256; + else + block_size = ent.dngdos_last_or_next; + + done = true; + } + } + else if( extent == (ent.flag_byte & DGNDOS_CONTINUATION_BIT ? CONT_EXTENTS_COUNT : HEADER_EXTENTS_COUNT) - 1) + { + if( !(ent.flag_byte & DGNDOS_CONTINUED_BIT) ) + { + // is last extent, and no continuation + if( ent.dngdos_last_or_next == 0 ) + block_size = 256; + else + block_size = ent.dngdos_last_or_next; + + done = true; + } + } + + err = dgndos_convert_lsn(entire_track20, lsn + i, &head, &track, §or ); + if(err) return err; + + err = imgtool_floppy_read_sector_to_stream(image, head, track, sector, 0, block_size, destf); + if (err) return err; + + extent++; + + if( extent == (ent.flag_byte & DGNDOS_CONTINUATION_BIT ? CONT_EXTENTS_COUNT : HEADER_EXTENTS_COUNT) ) + { + if( ent.flag_byte & DGNDOS_CONTINUED_BIT) + { + position = ent.dngdos_last_or_next; + err = get_dgndos_dirent(entire_track20, ent.dngdos_last_or_next, ent ); + if(err) return err; + + extent = 0; + directory_entry_count++; + } + } + } + while( !done ); + + return IMGTOOLERR_SUCCESS; +} + +static imgtoolerr_t dgndos_diskimage_deletefile(imgtool::partition &partition, const char *fname) +{ + imgtoolerr_t err; + floperr_t ferr; + imgtool::image &image(partition.image()); + int pos; + struct dgndos_dirent ent; + int directory_entry_count = 0; + + uint8_t entire_track20[18*256]; + uint8_t entire_track16[18*256]; + bool write_20_to_16; + + ferr = dgndos_get_directory_track( image, 20, entire_track20 ); + if (ferr) return imgtool_floppy_error(ferr); + + ferr = dgndos_get_directory_track( image, 16, entire_track16 ); + if (ferr) return imgtool_floppy_error(ferr); + + write_20_to_16 = memcmp(entire_track20, entire_track16, 256*18 ); + + err = lookup_dgndos_file(entire_track20, fname, ent, &pos); + if (err) return err; + + ent.flag_byte |= DGNDOS_DELETED_BIT; + ent.flag_byte &= ~DGNDOS_PROTECT_BIT; + + for( int i=0; i<HEADER_EXTENTS_COUNT; i++) + { + if( ent.block.header.block[i].count != 0) + { + dgndos_fat_deallocate_span(entire_track20, big_endianize_int16(ent.block.header.block[i].lsn), ent.block.header.block[i].count); + + ent.block.header.block[i].lsn = 0; + ent.block.header.block[i].count = 0; + } + else break; + } + + int continue_flag = ent.flag_byte & DGNDOS_CONTINUED_BIT; + int continue_dirent_index = ent.dngdos_last_or_next; + + ent.dngdos_last_or_next = 0; + err = put_dgndos_dirent(entire_track20, pos, ent); + if (err) return err; + + while( continue_flag ) + { + if( directory_entry_count > MAX_DIRENTS ) return IMGTOOLERR_CORRUPTDIR; + + int dirent_index = continue_dirent_index; + err = get_dgndos_dirent(entire_track20, dirent_index, ent); + if (err) return err; + + for( int i=0; i<CONT_EXTENTS_COUNT; i++) + { + if(ent.block.continuation.block[i].count !=0) + { + dgndos_fat_deallocate_span(entire_track20, big_endianize_int16(ent.block.continuation.block[i].lsn), ent.block.continuation.block[i].count); + + ent.block.continuation.block[i].lsn = 0; + ent.block.continuation.block[i].count = 0; + } + else break; + } + + ent.flag_byte |= DGNDOS_DELETED_BIT; + continue_flag = ent.flag_byte & DGNDOS_CONTINUED_BIT; + continue_dirent_index = ent.dngdos_last_or_next; + + ent.dngdos_last_or_next = 0; + err = put_dgndos_dirent(entire_track20, dirent_index, ent); + if (err) return err; + + directory_entry_count++; + } + + ferr = dgndos_put_directory_track( image, 20, entire_track20 ); + if (ferr) return imgtool_floppy_error(ferr); + + if( write_20_to_16 ) + { + ferr = dgndos_put_directory_track( image, 16, entire_track20 ); + if (ferr) return imgtool_floppy_error(ferr); + } + + return IMGTOOLERR_SUCCESS; +} + +static imgtoolerr_t dgndos_prepare_dirent(uint8_t *track, dgndos_dirent &ent, const char *fname) +{ + const char *fname_end; + const char *fname_ext; + int fname_ext_len; + + memset(&ent, '\0', sizeof(ent)); + + fname_end = strchr(fname, '.'); + if (fname_end) + fname_ext = fname_end + 1; + else + fname_end = fname_ext = fname + strlen(fname); + + fname_ext_len = strlen(fname_ext); + + // we had better be an 8.3 filename + if (((fname_end - fname) > 8) || (fname_ext_len > 3)) + return IMGTOOLERR_BADFILENAME; + + memcpy(&ent.block.header.filename[0], fname, fname_end - fname); + memcpy(&ent.block.header.filename[8], fname_ext, fname_ext_len); + + return IMGTOOLERR_SUCCESS; +} + +static imgtoolerr_t dgndos_diskimage_writefile(imgtool::partition &partition, const char *fname, const char *fork, imgtool::stream &sourcef, util::option_resolution *writeoptions) +{ + floperr_t ferr; + imgtoolerr_t err; + imgtool::image &image(partition.image()); + dgndos_dirent ent; + int position; + uint64_t written = 0; + int fat_block, first_lsn, sectors_avaiable, current_sector_index; + int last_sector_size = 0; + int bitmap_count; + + if( sourcef.size() == 0 ) return IMGTOOLERR_BUFFERTOOSMALL; + + uint8_t entire_track20[18*256]; + uint8_t entire_track16[18*256]; + bool write_20_to_16; + + ferr = dgndos_get_directory_track( image, 20, entire_track20 ); + if (ferr) return imgtool_floppy_error(ferr); + + ferr = dgndos_get_directory_track( image, 16, entire_track16 ); + if (ferr) return imgtool_floppy_error(ferr); + + write_20_to_16 = memcmp(entire_track20, entire_track16, 18*256 ); + + err = dgndos_get_geometry(entire_track20, &bitmap_count, nullptr, nullptr, nullptr); + if(err) return err; + + // find directory entry with same file name + err = lookup_dgndos_file(entire_track20, fname, ent, &position); + + if( err == IMGTOOLERR_FILENOTFOUND ) + { + int new_lsn; + + // get new directory entry + err = dgndos_get_avaiable_dirent(entire_track20, ent, &position); + if (err) return err; + + err = dgndos_prepare_dirent(entire_track20, ent, fname); + if(err) return err; + + err = dgndos_get_avaiable_sector( entire_track20, &new_lsn ); + if (err) + { + return err; + } + + dgndos_fat_allocate_sector(entire_track20, new_lsn); + + ent.block.header.block[0].lsn = big_endianize_int16(new_lsn); + ent.block.header.block[0].count = 1; + + err = put_dgndos_dirent(entire_track20, position, ent); + if(err) return err; + } + else if(err != IMGTOOLERR_SUCCESS ) + { + return err; + } + + if( writeoptions->lookup_int(DGNDOS_OPTIONS_PROTECT)) + { + ent.flag_byte |= DGNDOS_PROTECT_BIT; + } + else + { + ent.flag_byte &= ~DGNDOS_PROTECT_BIT; + } + + fat_block = 0; + + /* get next available fat entry */ + first_lsn = big_endianize_int16(ent.block.header.block[fat_block].lsn); + sectors_avaiable = ent.block.header.block[fat_block].count; + current_sector_index = 0; + + do + { + while ((current_sector_index < sectors_avaiable) && (written < sourcef.size())) + { + int head, track, sector, write_count; + + err = dgndos_convert_lsn(entire_track20, first_lsn + current_sector_index, &head, &track, §or ); + if (err) return err; + + if( sourcef.size() - written > 256 ) + { + write_count = 256; + } + else if( sourcef.size() - written == 256 ) + { + write_count = 256; + last_sector_size = 0; + } + else + { + write_count = sourcef.size() - written; + last_sector_size = write_count; + } + + err = imgtool_floppy_write_sector_from_stream(image, head, track, sector, 0, write_count, sourcef); + if (err) return err; + + current_sector_index++; + written += write_count; + } + + if( written == sourcef.size()) // are we are done writing file + { + int de_count = 0; + int de_dont_delete = position; + int lsn, count; + int save_next_de; + + save_next_de = ent.dngdos_last_or_next; + ent.dngdos_last_or_next = last_sector_size; + + // yes, truncate this allocation block if necessary + if( ent.flag_byte & DGNDOS_CONTINUATION_BIT) + { + for( int i = current_sector_index; i < ent.block.continuation.block[fat_block].count; i++) + { + dgndos_fat_deallocate_sector(entire_track20, first_lsn + i); + } + + ent.block.continuation.block[fat_block].count = current_sector_index; + } + else + { + for( int i = current_sector_index; i < ent.block.header.block[fat_block].count; i++) + { + dgndos_fat_deallocate_sector(entire_track20, first_lsn + i); + } + + ent.block.header.block[fat_block].count = current_sector_index; + } + + do // check remaining allocation blocks and zero them + { + fat_block++; + + if( (fat_block < (ent.flag_byte & DGNDOS_CONTINUATION_BIT ? CONT_EXTENTS_COUNT : HEADER_EXTENTS_COUNT)) ) + { + lsn = big_endianize_int16( ent.flag_byte & DGNDOS_CONTINUATION_BIT ? ent.block.continuation.block[fat_block].lsn : ent.block.header.block[fat_block].lsn ); + count = ent.flag_byte & DGNDOS_CONTINUATION_BIT ? ent.block.continuation.block[fat_block].count : ent.block.header.block[fat_block].count; + + if( count > 0 ) + { + dgndos_fat_deallocate_span(entire_track20, lsn, count); + + (ent.flag_byte & DGNDOS_CONTINUATION_BIT ? ent.block.continuation.block[fat_block].lsn : ent.block.header.block[fat_block].lsn) = 0; + (ent.flag_byte & DGNDOS_CONTINUATION_BIT ? ent.block.continuation.block[fat_block].count : ent.block.header.block[fat_block].count) = 0; + } + } + else + { + uint8_t save_flag = ent.flag_byte; + + ent.flag_byte &= ~DGNDOS_CONTINUED_BIT; + + if( ent.flag_byte & DGNDOS_CONTINUATION_BIT ) + { + if( de_dont_delete != position ) + { + ent.flag_byte |= DGNDOS_DELETED_BIT; + } + } + + err = put_dgndos_dirent(entire_track20, position, ent); + if (err) return err; + + if( save_flag & DGNDOS_CONTINUED_BIT ) + { + position = save_next_de; + + err = get_dgndos_dirent(entire_track20, position, ent); + if (err) return err; + + save_next_de = ent.dngdos_last_or_next; + fat_block = -1; + } + else + { + break; + } + } + + de_count++; + } + while( de_count < MAX_DIRENTS ); + + if( de_count == MAX_DIRENTS ) return IMGTOOLERR_CORRUPTDIR; + } + else // more to write + { + // check if I can extend the allocation count + if( (current_sector_index < 254) && (first_lsn + current_sector_index < bitmap_count) && (dgndos_is_sector_avaiable( entire_track20, first_lsn + current_sector_index )) ) + { + sectors_avaiable++; + + (ent.flag_byte & DGNDOS_CONTINUATION_BIT ? ent.block.continuation.block[fat_block].count : ent.block.header.block[fat_block].count) = sectors_avaiable; + + dgndos_fat_allocate_sector( entire_track20, first_lsn + current_sector_index ); + } + else // this allocation list is full - check next allocation list + { + fat_block++; + + if( fat_block == (ent.flag_byte & DGNDOS_CONTINUATION_BIT ? CONT_EXTENTS_COUNT : HEADER_EXTENTS_COUNT)) + { + if( ent.flag_byte & DGNDOS_CONTINUED_BIT) + { + // go to next directory entry. + err = put_dgndos_dirent(entire_track20, position, ent); + if (err) return err; + + position = ent.dngdos_last_or_next; + err = get_dgndos_dirent(entire_track20, position, ent); + if (err) + { + return err; + } + + fat_block = 0; + } + else + { + // need a or another continuation directory entry + int save_position = position, new_lsn; + + err = put_dgndos_dirent(entire_track20, position, ent); + if (err) return err; + + err = dgndos_get_avaiable_dirent_position( entire_track20, &position ); + if (err) + { + return err; + } + + ent.flag_byte |= DGNDOS_CONTINUED_BIT; + ent.dngdos_last_or_next = position; + err = put_dgndos_dirent(entire_track20, save_position, ent); + if (err) return err; + + err = get_dgndos_dirent(entire_track20, position, ent); + if (err) + { + return err; + } + + memset( (void *)&ent, 0, sizeof(dgndos_dirent) ); + ent.flag_byte |= DGNDOS_CONTINUATION_BIT; + fat_block = 0; + + err = dgndos_get_avaiable_sector( entire_track20, &new_lsn ); + if (err) + { + return err; + } + } + } + + sectors_avaiable = ent.flag_byte & DGNDOS_CONTINUATION_BIT ? ent.block.continuation.block[fat_block].count : ent.block.header.block[fat_block].count; + + // check if this block is empty + if( sectors_avaiable == 0) + { + int new_lsn; + + err = dgndos_get_avaiable_sector( entire_track20, &new_lsn ); + if (err) return err; + + (ent.flag_byte & DGNDOS_CONTINUATION_BIT ? ent.block.continuation.block[fat_block].lsn : ent.block.header.block[fat_block].lsn) = big_endianize_int16(new_lsn); + (ent.flag_byte & DGNDOS_CONTINUATION_BIT ? ent.block.continuation.block[fat_block].count : ent.block.header.block[fat_block].count) = 1; + + dgndos_fat_allocate_sector(entire_track20, new_lsn); + } + + first_lsn = ent.flag_byte & DGNDOS_CONTINUATION_BIT ? big_endianize_int16(ent.block.continuation.block[fat_block].lsn) : big_endianize_int16(ent.block.header.block[fat_block].lsn); + sectors_avaiable = ent.flag_byte & DGNDOS_CONTINUATION_BIT ? ent.block.continuation.block[fat_block].count : ent.block.header.block[fat_block].count; + current_sector_index = 0; + } + } + } + while( written < sourcef.size() ); + + ferr = dgndos_put_directory_track( image, 20, entire_track20 ); + if (ferr) return imgtool_floppy_error(ferr); + + if( write_20_to_16 ) + { + ferr = dgndos_put_directory_track( image, 16, entire_track20 ); + if (ferr) return imgtool_floppy_error(ferr); + } + + return IMGTOOLERR_SUCCESS; +} + +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; + imgtool::image &image(partition.image()); + struct dgndos_dirent ent; + int pos; + + uint8_t entire_track20[18*256]; + + ferr = dgndos_get_directory_track( image, 20, entire_track20 ); + if (ferr) return imgtool_floppy_error(ferr); + + if (fname) + { + err = lookup_dgndos_file(entire_track20, fname, ent, &pos); + if (err) + return err; + + if (strcmp(ent.block.header.filename+8,"DAT") == 0) + { + /* ASCII file */ + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; + suggestions[0].filter = filter_eoln_getinfo; + 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 = imgtool::SUGGESTION_RECOMMENDED; + suggestions[0].filter = nullptr; + suggestions[1].viability = imgtool::SUGGESTION_POSSIBLE; + suggestions[1].filter = filter_dragonbas_getinfo; + } + } + else + { + 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 = imgtool::SUGGESTION_POSSIBLE; + suggestions[2].filter = filter_dragonbas_getinfo; + } + + return IMGTOOLERR_SUCCESS; +} + +static imgtoolerr_t dgndos_diskimage_create(imgtool::image &image, imgtool::stream::ptr &&stream, util::option_resolution *opts) +{ + imgtoolerr_t err; + uint32_t heads, tracks, sectors, first_sector_id, sector_bytes, total_sector_count; + uint8_t sector[512]; + struct dgndos_dirent *ents; + + heads = opts->lookup_int('H'); + tracks = opts->lookup_int('T'); + sectors = opts->lookup_int('S'); + first_sector_id = opts->lookup_int('F'); + sector_bytes = opts->lookup_int('L'); + + if(sector_bytes!=256) return IMGTOOLERR_UNIMPLEMENTED; + + // create FAT sectors + memset( sector, 0, 512 ); + + total_sector_count = (heads * tracks * sectors); + + for( int i=0; i<total_sector_count; i++ ) + { + dgndos_fat_deallocate_sector(sector, i); + } + + sector[0xfc] = tracks; + sector[0xfd] = heads == 1 ? (sectors) : (sectors * 2); + sector[0xfe] = ~sector[0xfc]; + sector[0xff] = ~sector[0xfd]; + + // allocate sectors + for( int i=0; i<18; i++ ) + { + dgndos_fat_allocate_sector(sector, (20 * 18 * heads) + i); + dgndos_fat_allocate_sector(sector, (16 * 18 * heads) + i); + } + + // write fat sectors + err = (imgtoolerr_t)floppy_write_sector(imgtool_floppy(image), 0, 20, first_sector_id, 0, §or[0], sector_bytes, 0); + if (err) return err; + err = (imgtoolerr_t)floppy_write_sector(imgtool_floppy(image), 0, 20, first_sector_id+1, 0, §or[256], sector_bytes, 0); + if (err) return err; + + err = (imgtoolerr_t)floppy_write_sector(imgtool_floppy(image), 0, 16, first_sector_id, 0, §or[0], sector_bytes, 0); + if (err) return err; + err = (imgtoolerr_t)floppy_write_sector(imgtool_floppy(image), 0, 16, first_sector_id+1, 0, §or[256], sector_bytes, 0); + if (err) return err; + + // create empty directory entries + memset( sector, 0, 512 ); + ents = (struct dgndos_dirent *)sector; + + for( int i=0; i<10; i++ ) + { + ents[i].flag_byte = 0x89; + } + + // write directory entires to disk + for( int i=3; i<19; i++) + { + err = (imgtoolerr_t)floppy_write_sector(imgtool_floppy(image), 0, 20, i, 0, §or[0], sector_bytes, 0); + if (err) return err; + err = (imgtoolerr_t)floppy_write_sector(imgtool_floppy(image), 0, 16, i, 0, §or[0], sector_bytes, 0); + if (err) return err; + } + + return IMGTOOLERR_SUCCESS; +} + +/********************************************************************* + Imgtool module declaration +*********************************************************************/ + +OPTION_GUIDE_START( dragon_dgndos_writefile_optionguide ) + OPTION_ENUM_START( DGNDOS_OPTIONS_PROTECT, "prot", "Protect file" ) + OPTION_ENUM( 0, "no", "No" ) + OPTION_ENUM( 1, "yes", "Yes" ) + OPTION_ENUM_END +OPTION_GUIDE_END + +void dgndos_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info) +{ + switch(state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + 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 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; + case IMGTOOLINFO_STR_EOLN: strcpy(info->s = imgtool_temp_str(), "\r"); break; + case IMGTOOLINFO_STR_WRITEFILE_OPTSPEC: strcpy(info->s = imgtool_temp_str(), "P[0]-1"); 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_FLOPPY_CREATE: info->create = dgndos_diskimage_create; break; + case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = dgndos_diskimage_nextenum; break; + case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = dgndos_diskimage_freespace; break; + case IMGTOOLINFO_PTR_READ_FILE: info->read_file = dgndos_diskimage_readfile; break; + case IMGTOOLINFO_PTR_WRITE_FILE: info->write_file = dgndos_diskimage_writefile; break; + case IMGTOOLINFO_PTR_DELETE_FILE: info->delete_file = dgndos_diskimage_deletefile; break; + case IMGTOOLINFO_PTR_SUGGEST_TRANSFER: info->suggest_transfer = dgndos_diskimage_suggesttransfer; break; + case IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE: info->writefile_optguide = &dragon_dgndos_writefile_optionguide; break; + case IMGTOOLINFO_PTR_FLOPPY_FORMAT: info->p = (void *) floppyoptions_coco; break; + } +} diff --git a/src/tools/imgtool/modules/fat.cpp b/src/tools/imgtool/modules/fat.cpp index 029050d1e9c..d6611932c0d 100644 --- a/src/tools/imgtool/modules/fat.cpp +++ b/src/tools/imgtool/modules/fat.cpp @@ -134,13 +134,17 @@ ****************************************************************************/ -#include <time.h> -#include <ctype.h> -#include "imgtool.h" -#include "formats/imageutl.h" -#include "unicode.h" #include "fat.h" +#include "corestr.h" +#include "multibyte.h" +#include "unicode.h" + +#include <algorithm> +#include <cctype> +#include <cstdio> +#include <ctime> + #define FAT_DIRENT_SIZE 32 #define FAT_SECLEN 512 @@ -176,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; @@ -364,14 +380,12 @@ static imgtoolerr_t fat_write_sector(imgtool::partition &partition, uint32_t sec } -#ifdef UNUSED_FUNCTION -static imgtoolerr_t fat_clear_sector(imgtool::partition &partition, uint32_t sector_index, uint8_t data) +[[maybe_unused]] static imgtoolerr_t fat_clear_sector(imgtool::partition &partition, uint32_t sector_index, uint8_t data) { char buf[FAT_SECLEN]; memset(buf, data, sizeof(buf)); return fat_write_sector(partition, sector_index, 0, buf, sizeof(buf)); } -#endif static imgtoolerr_t fat_partition_open(imgtool::partition &partition, uint64_t first_block, uint64_t block_count) @@ -410,19 +424,19 @@ static imgtoolerr_t fat_partition_open(imgtool::partition &partition, uint64_t f } info->fat_bits = fat_bits; - sector_size = pick_integer_le(header, 11, 2); - info->sectors_per_cluster = pick_integer_le(header, 13, 1); - info->reserved_sectors = pick_integer_le(header, 14, 2); - info->fat_count = pick_integer_le(header, 16, 1); - info->root_entries = pick_integer_le(header, 17, 2); - total_sectors_l = pick_integer_le(header, 19, 2); - info->sectors_per_fat = pick_integer_le(header, 22, 2); - total_sectors_h = pick_integer_le(header, 32, 4); + sector_size = get_u16le(&header[11]); + info->sectors_per_cluster = header[13]; + info->reserved_sectors = get_u16le(&header[14]); + info->fat_count = header[16]; + info->root_entries = get_u16le(&header[17]); + total_sectors_l = get_u16le(&header[19]); + info->sectors_per_fat = get_u16le(&header[22]); + total_sectors_h = get_u32le(&header[32]); if (info->sectors_per_cluster == 0) return IMGTOOLERR_CORRUPTIMAGE; - info->total_sectors = total_sectors_l + (((uint64_t) total_sectors_h) << 16); + info->total_sectors = total_sectors_l + (uint64_t(total_sectors_h) << 16); available_sectors = info->total_sectors - info->reserved_sectors - (info->sectors_per_fat * info->fat_count) - (info->root_entries * FAT_DIRENT_SIZE + FAT_SECLEN - 1) / FAT_SECLEN; @@ -520,24 +534,24 @@ static imgtoolerr_t fat_partition_create(imgtool::image &image, uint64_t first_b /* prepare the header */ memset(header, 0, sizeof(header)); memcpy(&header[3], "IMGTOOL ", 8); - place_integer_le(header, 11, 2, FAT_SECLEN); - place_integer_le(header, 13, 1, sectors_per_cluster); - place_integer_le(header, 14, 1, reserved_sectors); - place_integer_le(header, 16, 1, fat_count); - place_integer_le(header, 17, 2, root_dir_count); - place_integer_le(header, 19, 2, (uint16_t) (block_count >> 0)); - place_integer_le(header, 21, 1, media_descriptor); - place_integer_le(header, 22, 2, sectors_per_fat); - place_integer_le(header, 24, 2, sectors_per_track); - place_integer_le(header, 26, 2, heads); - place_integer_le(header, 28, 4, hidden_sectors); - place_integer_le(header, 32, 4, (uint32_t) (block_count >> 16)); - place_integer_le(header, 36, 1, 0xFF); - place_integer_le(header, 38, 1, 0x28); - place_integer_le(header, 39, 1, std::rand()); - place_integer_le(header, 40, 1, std::rand()); - place_integer_le(header, 41, 1, std::rand()); - place_integer_le(header, 42, 1, std::rand()); + put_u16le(&header[11], FAT_SECLEN); + header[13] = sectors_per_cluster; + header[14] = reserved_sectors; + header[16] = fat_count; + put_u16le(&header[17], root_dir_count); + put_u16le(&header[19], uint16_t(block_count >> 0)); + header[21] = media_descriptor; + put_u16le(&header[22], sectors_per_fat); + put_u16le(&header[24], sectors_per_track); + put_u16le(&header[26], heads); + put_u32le(&header[28], hidden_sectors); + put_u32le(&header[32], uint32_t(block_count >> 16)); + header[36] = 0xFF; + header[38] = 0x28; + header[39] = std::rand(); + header[40] = std::rand(); + header[41] = std::rand(); + header[42] = std::rand(); memcpy(&header[43], " ", 11); memcpy(&header[54], fat_bits_string, 8); @@ -553,14 +567,14 @@ static imgtoolerr_t fat_partition_create(imgtool::image &image, uint64_t first_b if (boot_sector_offset <= 129) { header[0] = 0xEB; /* JMP rel8 */ - header[1] = (uint8_t) (boot_sector_offset - 2); /* (offset) */ + header[1] = uint8_t(boot_sector_offset - 2); /* (offset) */ header[2] = 0x90; /* NOP */ } else { header[0] = 0xE9; /* JMP rel16 */ - header[1] = (uint8_t) ((boot_sector_offset - 2) >> 0); /* (offset) */ - header[2] = (uint8_t) ((boot_sector_offset - 2) >> 8); /* (offset) */ + header[1] = uint8_t((boot_sector_offset - 2) >> 0); /* (offset) */ + header[2] = uint8_t((boot_sector_offset - 2) >> 8); /* (offset) */ } err = image.write_block(first_block, header); @@ -578,9 +592,9 @@ static imgtoolerr_t fat_partition_create(imgtool::image &image, uint64_t first_b // FIXME: this causes a corrupt PC floppy image since it doubles the FAT partition header - works without it though #if 0 /* set first two FAT entries */ - first_fat_entries = ((uint64_t) media_descriptor) | 0xFFFFFF00; - first_fat_entries &= (((uint64_t) 1) << fat_bits) - 1; - first_fat_entries |= ((((uint64_t) 1) << fat_bits) - 1) << fat_bits; + first_fat_entries = uint64_t(media_descriptor) | 0xFFFFFF00; + first_fat_entries &= (uint64_t(1) << fat_bits) - 1; + first_fat_entries |= ((uint64_t(1) << fat_bits) - 1) << fat_bits; first_fat_entries = little_endianize_int64(first_fat_entries); for (i = 0; i < fat_count; i++) @@ -706,8 +720,8 @@ static uint32_t fat_get_fat_entry(imgtool::partition &partition, const uint8_t * entry &= bit_mask; if (i == 0) - last_entry = (uint32_t) entry; - else if (last_entry != (uint32_t) entry) + last_entry = uint32_t(entry); + else if (last_entry != uint32_t(entry)) return 1; /* if the FATs disagree; mark this as reserved */ } @@ -739,8 +753,8 @@ static void fat_set_fat_entry(imgtool::partition &partition, uint8_t *fat_table, * disk_info->sectors_per_fat) + (bit_index / 8), sizeof(entry)); entry = little_endianize_int64(entry); - entry &= (~((uint64_t) 0xFFFFFFFF >> (32 - disk_info->fat_bits)) << (bit_index % 8)) | ((1 << (bit_index % 8)) - 1); - entry |= ((uint64_t) value) << (bit_index % 8); + entry &= (~(uint64_t(0xFFFFFFFF) >> (32 - disk_info->fat_bits)) << (bit_index % 8)) | ((1 << (bit_index % 8)) - 1); + entry |= uint64_t(value) << (bit_index % 8); entry = little_endianize_int64(entry); memcpy(fat_table + (i * FAT_SECLEN @@ -1080,8 +1094,8 @@ static imgtoolerr_t fat_set_file_size(imgtool::partition &partition, fat_file *f } /* record the new file size */ - place_integer_le(dirent, 26, 2, file->first_cluster); - place_integer_le(dirent, 28, 4, new_size); + put_u16le(&dirent[26], file->first_cluster); + put_u32le(&dirent[28], new_size); /* delete the file, if appropriate */ if (delete_file) @@ -1228,7 +1242,7 @@ static void fat_canonicalize_sfn(char *sfn, const uint8_t *sfn_bytes) memcpy(sfn, sfn_bytes, 8); rtrim(sfn); if (sfn[0] == 0x05) - sfn[0] = (char) 0xE5; + sfn[0] = char(0xE5); if ((sfn_bytes[8] != ' ') || (sfn_bytes[9] != ' ') || (sfn_bytes[10] != ' ')) { strcat(sfn, "."); @@ -1272,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; @@ -1289,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 @@ -1326,11 +1341,11 @@ static imgtoolerr_t fat_read_dirent(imgtool::partition &partition, fat_file *fil lfn_checksum = entry[13]; } lfn_lastentry = entry[0] & 0x3F; - prepend_lfn_bytes(lfn_buf, ARRAY_LENGTH(lfn_buf), + prepend_lfn_bytes(lfn_buf, std::size(lfn_buf), &lfn_len, entry, 28, 2); - prepend_lfn_bytes(lfn_buf, ARRAY_LENGTH(lfn_buf), + prepend_lfn_bytes(lfn_buf, std::size(lfn_buf), &lfn_len, entry, 14, 6); - prepend_lfn_bytes(lfn_buf, ARRAY_LENGTH(lfn_buf), + prepend_lfn_bytes(lfn_buf, std::size(lfn_buf), &lfn_len, entry, 1, 5); } else if (freeent && (freeent->position == ~0)) @@ -1350,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') @@ -1368,25 +1383,25 @@ 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], ARRAY_LENGTH(lfn_buf) - i); - j += utf8_from_uchar(&ent.long_filename[j], ARRAY_LENGTH(ent.long_filename) - j, ch); + 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); } } /* other attributes */ - ent.filesize = pick_integer_le(entry, 28, 4); + ent.filesize = get_u32le(&entry[28]); ent.directory = (entry[11] & 0x10) ? 1 : 0; - ent.first_cluster = pick_integer_le(entry, 26, 2); + ent.first_cluster = get_u16le(&entry[26]); ent.dirent_sector_index = entry_sector_index; ent.dirent_sector_offset = entry_sector_offset; - ent.creation_time = fat_crack_time(pick_integer_le(entry, 14, 4)); - ent.lastmodified_time = fat_crack_time(pick_integer_le(entry, 22, 4)); + ent.creation_time = fat_crack_time(get_u32le(&entry[14])); + ent.lastmodified_time = fat_crack_time(get_u32le(&entry[22])); return IMGTOOLERR_SUCCESS; } @@ -1440,9 +1455,9 @@ static imgtoolerr_t fat_construct_dirent(const char *filename, creation_policy_t /* set up file dates in the new dirent */ now = fat_setup_time(time(NULL)); - place_integer_le(created_entry, 14, 4, now); - place_integer_le(created_entry, 18, 2, now); - place_integer_le(created_entry, 22, 4, now); + put_u32le(&created_entry[14], now); + put_u16le(&created_entry[18], now); + put_u32le(&created_entry[22], now); while(*filename) { @@ -1451,13 +1466,13 @@ static imgtoolerr_t fat_construct_dirent(const char *filename, creation_policy_t /* append to short filename, if possible */ if ((ch < 32) || (ch > 128)) short_char = '\0'; - else if (isalnum((char) ch)) - short_char = toupper((char) ch); - else if (strchr(".!#$%^()-@^_`{}~", (char) ch)) - short_char = (char) ch; + else if (isalnum(char(ch))) + short_char = toupper(char(ch)); + else if (strchr(".!#$%^()-@^_`{}~", char(ch))) + short_char = char(ch); else short_char = '\0'; /* illegal SFN char */ - canonical_short_char = fat_canonicalize_sfn_char((char) ch); + canonical_short_char = fat_canonicalize_sfn_char(char(ch)); if (!short_char || (short_char != canonical_short_char)) { if (toupper(short_char) == toupper(canonical_short_char)) @@ -1605,7 +1620,7 @@ static void fat_bump_dirent(imgtool::partition &partition, uint8_t *entry, size_ sfn_entry = &entry[entry_len - FAT_DIRENT_SIZE]; digit_place = 1; - for (pos = 7; (pos >= 0) && isdigit((char) sfn_entry[pos]); pos--) + for (pos = 7; (pos >= 0) && isdigit(char(sfn_entry[pos])); pos--) { val += (sfn_entry[pos] - '0') * digit_place; digit_place *= 10; @@ -1834,7 +1849,7 @@ static imgtoolerr_t fat_partition_nextenum(imgtool::directory &enumeration, imgt return err; /* copy stuff from the FAT dirent to the Imgtool dirent */ - snprintf(ent.filename, ARRAY_LENGTH(ent.filename), "%s", fatent.long_filename[0] + snprintf(ent.filename, std::size(ent.filename), "%s", fatent.long_filename[0] ? fatent.long_filename : fatent.short_filename); ent.filesize = fatent.filesize; ent.directory = fatent.directory; @@ -1945,7 +1960,7 @@ static imgtoolerr_t fat_partition_writefile(imgtool::partition &partition, const if (file.directory) return IMGTOOLERR_FILENOTFOUND; - bytes_left = (uint32_t) sourcef.size(); + bytes_left = uint32_t(sourcef.size()); err = fat_set_file_size(partition, &file, bytes_left); if (err) @@ -2051,11 +2066,11 @@ static imgtoolerr_t fat_partition_createdir(imgtool::partition &partition, const /* set up the two directory entries in all directories */ memset(initial_data, 0, sizeof(initial_data)); memcpy(&initial_data[0], ". ", 11); - place_integer_le(initial_data, 11, 1, 0x10); - place_integer_le(initial_data, 26, 2, file.first_cluster); + initial_data[11] = 0x10; + put_u16le(&initial_data[26], file.first_cluster); memcpy(&initial_data[32], ". ", 11); - place_integer_le(initial_data, 43, 1, 0x10); - place_integer_le(initial_data, 58, 2, file.parent_first_cluster); + initial_data[43] = 0x10; + put_u16le(&initial_data[58], file.parent_first_cluster); err = fat_write_file(partition, &file, initial_data, sizeof(initial_data), NULL); if (err) diff --git a/src/tools/imgtool/modules/fat.h b/src/tools/imgtool/modules/fat.h index 77c56f5f9f1..8e7c60d89af 100644 --- a/src/tools/imgtool/modules/fat.h +++ b/src/tools/imgtool/modules/fat.h @@ -1,3 +1,6 @@ // license:BSD-3-Clause // copyright-holders:Raphael Nabet + +#include "imgtool.h" + void fat_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info); diff --git a/src/tools/imgtool/modules/hp48.cpp b/src/tools/imgtool/modules/hp48.cpp index 4d237f3c470..4a008adaeb5 100644 --- a/src/tools/imgtool/modules/hp48.cpp +++ b/src/tools/imgtool/modules/hp48.cpp @@ -86,6 +86,8 @@ #include "imgtool.h" +#include "opresolv.h" + /***************************************************************************** diff --git a/src/tools/imgtool/modules/hp85_tape.cpp b/src/tools/imgtool/modules/hp85_tape.cpp index dada87e290a..319f1e3f10c 100644 --- a/src/tools/imgtool/modules/hp85_tape.cpp +++ b/src/tools/imgtool/modules/hp85_tape.cpp @@ -7,12 +7,19 @@ HP-85 tape format *********************************************************************/ - #include "imgtool.h" -#include "formats/imageutl.h" + #include "formats/hti_tape.h" + +#include "ioprocs.h" +#include "multibyte.h" +#include "opresolv.h" +#include "strformat.h" + +#include <cstdio> #include <iostream> + // Constants static constexpr unsigned CHARS_PER_FNAME = 6; // Characters in a filename static constexpr unsigned CHARS_PER_EXT = 4; // Characters in (simulated) file extension @@ -109,9 +116,9 @@ private: // Content std::vector<sif_file_ptr_t> content; // First file on track 1 - file_no_t file_track_1; + file_no_t file_track_1{}; // No. of first record on track 1 - uint16_t record_track_1; + uint16_t record_track_1 = 0; bool dec_rec_header(const tape_word_t *hdr , file_no_t& file_no , uint16_t& rec_no , bool& has_body , unsigned& body_len); bool load_whole_tape(); @@ -145,7 +152,7 @@ typedef struct { tape_image_85::tape_image_85(void) : dirty(false) { - image.set_bits_per_word(16); + image.set_image_format(hti_format_t::HTI_DELTA_MOD_16_BITS); } void tape_image_85::format_img(void) @@ -158,48 +165,13 @@ void tape_image_85::format_img(void) finalize_allocation(); } -namespace { - int my_seekproc(void *file, int64_t offset, int whence) - { - reinterpret_cast<imgtool::stream *>(file)->seek(offset, whence); - return 0; - } - - size_t my_readproc(void *file, void *buffer, size_t length) - { - return reinterpret_cast<imgtool::stream *>(file)->read(buffer, length); - } - - size_t my_writeproc(void *file, const void *buffer, size_t length) - { - reinterpret_cast<imgtool::stream *>(file)->write(buffer, length); - return length; - } - - uint64_t my_filesizeproc(void *file) - { - return reinterpret_cast<imgtool::stream *>(file)->size(); - } - - const struct io_procs my_stream_procs = { - nullptr, - my_seekproc, - my_readproc, - my_writeproc, - my_filesizeproc - }; -} - imgtoolerr_t tape_image_85::load_from_file(imgtool::stream *stream) { - io_generic io; - io.file = (void *)stream; - io.procs = &my_stream_procs; - io.filler = 0; - - if (!image.load_tape(&io)) { + auto io = imgtool::stream_read(*stream, 0); + if (!io || !image.load_tape(*io)) { return IMGTOOLERR_READERROR; } + io.reset(); // Prevent track boundary crossing when reading directory file_track_1 = 0; @@ -422,12 +394,7 @@ imgtoolerr_t tape_image_85::save_to_file(imgtool::stream *stream) file_0.clear(); save_sif_file(track , pos , dir.size() + 1 , file_0); - io_generic io; - io.file = (void *)stream; - io.procs = &my_stream_procs; - io.filler = 0; - - image.save_tape(&io); + image.save_tape(*imgtool::stream_read_write(*stream, 0)); return IMGTOOLERR_SUCCESS; } @@ -667,7 +634,7 @@ bool tape_image_85::decode_dir(const sif_file_t& file_0) // Get FL1TK1 file_track_1 = file_0[ 0xfd ]; - record_track_1 = pick_integer_le(file_0.data() , 0xfe , 2); + record_track_1 = get_u16le(&file_0[ 0xfe ]); file_no_t file_no = 1; @@ -698,10 +665,10 @@ bool tape_image_85::decode_dir(const sif_file_t& file_0) new_entry.file_no = file_no++; // Physical records - new_entry.n_recs = pick_integer_le(p , 8 , 2); + new_entry.n_recs = get_u16le(&p[ 8 ]); // Bytes per logical record - new_entry.record_len = pick_integer_le(p , 10 , 2); + new_entry.record_len = get_u16le(&p[ 10 ]); if (new_entry.record_len < 4 || new_entry.record_len >= 32768) { return false; } @@ -722,8 +689,8 @@ void tape_image_85::encode_dir(sif_file_t& file_0) const file_0[ 0x1fc ] = 1; // Set FL1TK1 file_0[ 0xfd ] = file_0[ 0x1fd ] = file_track_1; - place_integer_le(file_0.data() , 0xfe , 2 , record_track_1); - place_integer_le(file_0.data() , 0x1fe , 2 , record_track_1); + put_u16le(&file_0[ 0xfe ] , record_track_1); + put_u16le(&file_0[ 0x1fe ] , record_track_1); unsigned i = 0; file_no_t file_no = 1; @@ -736,8 +703,8 @@ void tape_image_85::encode_dir(sif_file_t& file_0) const memcpy(&p_entry[ 0 ] , &entry->filename[ 0 ] , CHARS_PER_FNAME); p_entry[ 6 ] = file_no; p_entry[ 7 ] = entry->filetype; - place_integer_le(p_entry , 8 , 2 , entry->n_recs); - place_integer_le(p_entry , 10 , 2 , entry->record_len); + put_u16le(&p_entry[ 8 ] , entry->n_recs); + put_u16le(&p_entry[ 10 ] , entry->record_len); } if (file_no <= MAX_FILE_NO) { @@ -866,7 +833,7 @@ namespace { tape_image_85& get_tape_image(tape_state_t& ts) { if (ts.img == nullptr) { - ts.img = global_alloc(tape_image_85); + ts.img = new tape_image_85; } return *(ts.img); @@ -916,7 +883,7 @@ namespace { delete state.stream; // Free tape_image - global_free(&tape_image); + delete &tape_image; } imgtoolerr_t hp85_tape_begin_enum (imgtool::directory &enumeration, const char *path) diff --git a/src/tools/imgtool/modules/hp9845_tape.cpp b/src/tools/imgtool/modules/hp9845_tape.cpp index d3416deaefd..26cb2f4eb1c 100644 --- a/src/tools/imgtool/modules/hp9845_tape.cpp +++ b/src/tools/imgtool/modules/hp9845_tape.cpp @@ -108,12 +108,20 @@ these special characters. *********************************************************************/ -#include <bitset> - #include "imgtool.h" -#include "formats/imageutl.h" +#include "filter.h" + #include "formats/hti_tape.h" +#include "corefile.h" +#include "ioprocs.h" +#include "multibyte.h" +#include "opresolv.h" + +#include <bitset> +#include <cstdio> + + // Constants #define SECTOR_LEN 256 // Bytes in a sector #define WORDS_PER_SECTOR (SECTOR_LEN / 2) // 16-bit words in a sector payload @@ -291,49 +299,16 @@ void tape_image_t::format_img(void) dirty = true; } -static int my_seekproc(void *file, int64_t offset, int whence) -{ - reinterpret_cast<imgtool::stream *>(file)->seek(offset, whence); - return 0; -} - -static size_t my_readproc(void *file, void *buffer, size_t length) -{ - return reinterpret_cast<imgtool::stream *>(file)->read(buffer, length); -} - -static size_t my_writeproc(void *file, const void *buffer, size_t length) -{ - reinterpret_cast<imgtool::stream *>(file)->write(buffer, length); - return length; -} - -static uint64_t my_filesizeproc(void *file) -{ - return reinterpret_cast<imgtool::stream *>(file)->size(); -} - -static const struct io_procs my_stream_procs = { - nullptr, - my_seekproc, - my_readproc, - my_writeproc, - my_filesizeproc -}; - imgtoolerr_t tape_image_t::load_from_file(imgtool::stream *stream) { hti_format_t inp_image; - inp_image.set_bits_per_word(16); + inp_image.set_image_format(hti_format_t::HTI_DELTA_MOD_16_BITS); - io_generic io; - io.file = (void *)stream; - io.procs = &my_stream_procs; - io.filler = 0; - - if (!inp_image.load_tape(&io)) { + auto io = imgtool::stream_read(*stream, 0); + if (!io || !inp_image.load_tape(*io)) { return IMGTOOLERR_READERROR; } + io.reset(); unsigned exp_sector = 0; unsigned last_sector_on_track = SECTORS_PER_TRACK; @@ -523,12 +498,7 @@ imgtoolerr_t tape_image_t::save_to_file(imgtool::stream *stream) } } - io_generic io; - io.file = (void *)stream; - io.procs = &my_stream_procs; - io.filler = 0; - - out_image.save_tape(&io); + out_image.save_tape(*imgtool::stream_read_write(*stream, 0)); return IMGTOOLERR_SUCCESS; } @@ -985,7 +955,7 @@ static tape_state_t& get_tape_state(imgtool::image &img) static tape_image_t& get_tape_image(tape_state_t& ts) { if (ts.img == nullptr) { - ts.img = global_alloc(tape_image_t); + ts.img = new tape_image_t; } return *(ts.img); @@ -1034,7 +1004,7 @@ static void hp9845_tape_close(imgtool::image &image) delete state.stream; // Free tape_image - global_free(&tape_image); + delete &tape_image; } static imgtoolerr_t hp9845_tape_begin_enum (imgtool::directory &enumeration, const char *path) @@ -1374,7 +1344,7 @@ static imgtoolerr_t hp9845data_read_file(imgtool::partition &partition, const ch if (!get_record_part(*inp_data , tmp , 2)) { return IMGTOOLERR_READERROR; } - rec_type = (uint16_t)pick_integer_be(tmp , 0 , 2); + rec_type = get_u16be(&tmp[ 0 ]); switch (rec_type) { case REC_TYPE_EOR: // End of record: just skip it @@ -1397,7 +1367,7 @@ static imgtoolerr_t hp9845data_read_file(imgtool::partition &partition, const ch if (!get_record_part(*inp_data , tmp , 2)) { return IMGTOOLERR_READERROR; } - tmp_len = (unsigned)pick_integer_be(tmp , 0 , 2); + tmp_len = get_u16be(&tmp [ 0 ]); if (rec_type == REC_TYPE_FULLSTR || rec_type == REC_TYPE_1STSTR) { accum_len = tmp_len; @@ -1445,7 +1415,7 @@ static bool split_string_n_dump(const char *s , imgtool::stream &dest) unsigned free_len = len_to_eor(dest); if (free_len <= 4) { // Not enough free space at end of current record: fill with EORs - place_integer_be(tmp , 0 , 2 , REC_TYPE_EOR); + put_u16be(&tmp[ 0 ] , REC_TYPE_EOR); while (free_len) { if (dest.write(tmp , 2) != 2) { return false; @@ -1458,8 +1428,8 @@ static bool split_string_n_dump(const char *s , imgtool::stream &dest) // Free space to EOR enough for what's left of string break; } - place_integer_be(tmp , 0 , 2 , rec_type); - place_integer_be(tmp , 2 , 2 , s_len); + put_u16be(&tmp[ 0 ] , rec_type); + put_u16be(&tmp[ 2 ] , s_len); if (dest.write(tmp , 4) != 4 || dest.write(s, s_part_len) != s_part_len) { return false; @@ -1471,8 +1441,8 @@ static bool split_string_n_dump(const char *s , imgtool::stream &dest) } } - place_integer_be(tmp , 0 , 2 , at_least_one ? REC_TYPE_ENDSTR : REC_TYPE_FULLSTR); - place_integer_be(tmp , 2 , 2 , s_len); + put_u16be(&tmp[ 0 ] , at_least_one ? REC_TYPE_ENDSTR : REC_TYPE_FULLSTR); + put_u16be(&tmp[ 2 ] , s_len); if (dest.write(tmp , 4) != 4 || dest.write(s , s_len) != s_len) { return false; @@ -1528,7 +1498,7 @@ static imgtoolerr_t hp9845data_write_file(imgtool::partition &partition, const c // Fill free space of last record with EOFs unsigned free_len = len_to_eor(*out_data); uint8_t tmp[ 2 ]; - place_integer_be(tmp , 0 , 2 , REC_TYPE_EOF); + put_u16be(&tmp[ 0 ] , REC_TYPE_EOF); while (free_len) { if (out_data->write(tmp , 2 ) != 2) { @@ -1544,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/mac.cpp b/src/tools/imgtool/modules/mac.cpp deleted file mode 100644 index 90c68323f76..00000000000 --- a/src/tools/imgtool/modules/mac.cpp +++ /dev/null @@ -1,6439 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Raphael Nabet -/**************************************************************************** - - mac.c - - Handlers for Classic MacOS images (MFS and HFS formats). - - Raphael Nabet, 2003 - - TODO: - * add support for HFS write - -***************************************************************************** - - terminology: - disk block: 512-byte logical block. With sectors of 512 bytes, one logical - block is equivalent to one sector; when the sector size is not 512 - bytes, sectors are split or grouped to make 512-byte disk blocks. - allocation block: The File Manager always allocates logical disk blocks to - a file in groups called allocation blocks; an allocation block is - simply a group of consecutive logical blocks. The size of a volume's - allocation blocks depends on the capacity of the volume; there can be - at most 4094 (MFS) or 65535 (HFS) allocation blocks on a volume. - MFS (Macintosh File System): File system used by the early Macintosh. This - File system does not support folders (you may create folders on a MFS - disk, but such folders are not implemented on File System level but in - the Desktop file, and they are just a hint of how programs should list - files, i.e. you can't have two files with the same name on a volume - even if they are in two different folders), and it is not adequate for - large volumes. - HFS (Hierarchical File System): File system introduced with the HD20 - harddisk, the Macintosh Plus ROMs, and system 3.2 (IIRC). Contrary to - MFS, it supports hierarchical folders. Also, it is suitable for larger - volumes. - HFS+ (HFS Plus): New file system introduced with MacOS 8.1. It has a lot - in common with HFS, but it supports more allocation blocks (up to 4 - billions IIRC), and many extra features, including longer file names - (up to 255 UTF-16 Unicode chars). - tag data: with the GCR encoding, each disk block is associated with a 12 - (3.5" floppies) or 20 (HD20) byte tag record. This tag record contains - information on the block allocation status (whether it is allocated - in a file or free, which file is it belongs to, what offset the block - has in the file). This enables to recover all files whose data blocks - are still on the disk surface even if the disk catalog has been trashed - completely (though most file properties, like the name, type and - logical EOF, are not saved in the tag record and cannot be recovered). - - Organization of an MFS volume: - - Logical Contents Allocation block - block - - 0 - 1: System startup information - 2 - m: Master directory block (MDB) - + allocation block link pointers - m+1 - n: Directory file - n+1 - p-2: Other files and free space 0 - ((p-2)-(n+1))/k - p-1: Alternate MDB - p: Not used - usually, k = 2, m = 3, n = 16, p = 799 (SSDD 3.5" floppy) - with DSDD 3.5" floppy, I assume that p = 1599, but I don't know the other - values - - - Master Directory Block: - - Offset Length Description - ------ ------ ----------- - 0 2 Volume Signature - 2 4 Creation Date - 6 4 Last Modification Date - 10 2 Volume Attributes - 12 2 Number of Files In Root Directory - 14 2 First Block of Volume Bitmap - ... - - Links: - http://developer.apple.com/documentation/mac/Files/Files-99.html - http://developer.apple.com/documentation/mac/Files/Files-100.html - http://developer.apple.com/documentation/mac/Files/Files-101.html - http://developer.apple.com/documentation/mac/Files/Files-102.html - http://developer.apple.com/documentation/mac/Files/Files-103.html - http://developer.apple.com/documentation/mac/Files/Files-104.html - http://developer.apple.com/documentation/mac/Files/Files-105.html - http://developer.apple.com/documentation/mac/Files/Files-106.html - http://developer.apple.com/documentation/mac/Devices/Devices-121.html#MARKER-2-169 - http://developer.apple.com/documentation/mac/MoreToolbox/MoreToolbox-99.html - -*****************************************************************************/ - -#include <ctype.h> -#include <string.h> -#include <time.h> -#include <limits.h> -#include <stddef.h> - -#include "formats/imageutl.h" -#include "imgtool.h" -#include "macutil.h" -#include "iflopimg.h" -#include "formats/ap_dsk35.h" - -/* if 1, check consistency of B-Tree (most of the checks will eventually be - suppressed when the image is opened as read-only and only enabled when - the image is opened as read/write) */ -#define BTREE_CHECKS 1 -/* if 1, check consistency of tag data when we are at risk of corrupting the - disk (file write and allocation) */ -#define TAG_CHECKS 1 -/* if 1, check consistency of tag data when reading files (not recommended - IMHO) */ -#define TAG_EXTRA_CHECKS 0 - -#if 0 -#pragma mark MISCELLANEOUS UTILITIES -#endif - -struct UINT16BE -{ - uint8_t bytes[2]; -}; - -struct UINT24BE -{ - uint8_t bytes[3]; -}; - -struct UINT32BE -{ - uint8_t bytes[4]; -}; - -static inline uint16_t get_UINT16BE(UINT16BE word) -{ - return (word.bytes[0] << 8) | word.bytes[1]; -} - -static inline void set_UINT16BE(UINT16BE *word, uint16_t data) -{ - word->bytes[0] = (data >> 8) & 0xff; - word->bytes[1] = data & 0xff; -} - -#if 0 -static inline uint32_t get_UINT24BE(UINT24BE word) -{ - return (word.bytes[0] << 16) | (word.bytes[1] << 8) | word.bytes[2]; -} - -static inline void set_UINT24BE(UINT24BE *word, uint32_t data) -{ - word->bytes[0] = (data >> 16) & 0xff; - word->bytes[1] = (data >> 8) & 0xff; - word->bytes[2] = data & 0xff; -} -#endif - -static inline uint32_t get_UINT32BE(UINT32BE word) -{ - return (word.bytes[0] << 24) | (word.bytes[1] << 16) | (word.bytes[2] << 8) | word.bytes[3]; -} - -static inline void set_UINT32BE(UINT32BE *word, uint32_t data) -{ - word->bytes[0] = (data >> 24) & 0xff; - word->bytes[1] = (data >> 16) & 0xff; - word->bytes[2] = (data >> 8) & 0xff; - word->bytes[3] = data & 0xff; -} - -/* - Macintosh string: first byte is length -*/ -typedef uint8_t mac_str27[28]; -typedef uint8_t mac_str31[32]; -typedef uint8_t mac_str63[64]; -typedef uint8_t mac_str255[256]; - -/* - Macintosh type/creator code: 4 char value -*/ -typedef UINT32BE mac_type; - -/* - point record, with the y and x coordinates -*/ -struct mac_point -{ - UINT16BE v; /* actually signed */ - UINT16BE h; /* actually signed */ -}; - -/* - rect record, with the corner coordinates -*/ -struct mac_rect -{ - UINT16BE top; /* actually signed */ - UINT16BE left; /* actually signed */ - UINT16BE bottom;/* actually signed */ - UINT16BE right; /* actually signed */ -}; - -/* - FInfo (Finder file info) record -*/ -struct mac_FInfo -{ - mac_type type; /* file type */ - mac_type creator; /* file creator */ - UINT16BE flags; /* Finder flags */ - mac_point location; /* file's location in window */ - /* If set to {0, 0}, and the inited flag is - clear, the Finder will place the item - automatically */ - UINT16BE fldr; /* MFS: window that contains file */ - /* -3: trash */ - /* -2: desktop */ - /* -1: new folder template?????? */ - /* 0: disk window ("root") */ - /* > 0: specific folder, index of FOBJ resource??? */ - /* The FOBJ resource contains some folder info; - the name of the resource is the folder name. */ - /* HFS & HFS+: - System 7: The window in which the file???s icon appears - System 8: reserved (set to 0) */ -}; - -/* - FXInfo (Finder extended file info) record -- not found in MFS -*/ -struct mac_FXInfo -{ - UINT16BE iconID; /* System 7: An ID number for the file???s icon; the - numbers that identify icons are assigned by the - Finder */ - /* System 8: Reserved (set to 0) */ - UINT16BE reserved[3]; /* Reserved (set to 0) */ - uint8_t script; /* System 7: if high-bit is set, the script code - for displaying the file name; ignored otherwise */ - /* System 8: Extended flags MSB(?) */ - uint8_t XFlags; /* Extended flags */ - UINT16BE comment; /* System 7: Comment ID if high-bit is clear */ - /* System 8: Reserved (set to 0) */ - UINT32BE putAway; /* Put away folder ID (i.e. if the user moves the - file onto the desktop, the directory ID of the - folder from which the user moves the file is - saved here) */ -}; - -/* - DInfo (Finder folder info) record -- not found in MFS -*/ -struct mac_DInfo -{ - mac_rect rect; /* Folder's window bounds */ - UINT16BE flags; /* Finder flags, e.g. kIsInvisible, kNameLocked, etc */ - mac_point location; /* Location of the folder in parent window */ - /* If set to {0, 0}, and the initied flag is - clear, the Finder will place the item - automatically */ - UINT16BE view; /* System 7: The manner in which folders are - displayed */ - /* System 8: reserved (set to 0) */ -}; - -/* - DXInfo (Finder extended folder info) record -- not found in MFS -*/ -struct mac_DXInfo -{ - mac_point scroll; /* Scroll position */ - UINT32BE openChain; /* System 7: chain of directory IDs for open folders */ - /* System 8: reserved (set to 0) */ - uint8_t script; /* System 7: if high-bit is set, the script code - for displaying the folder name; ignored otherwise */ - /* System 8: Extended flags MSB(?) */ - uint8_t XFlags; /* Extended flags */ - UINT16BE comment; /* System 7: Comment ID if high-bit is clear */ - /* System 8: Reserved (set to 0) */ - UINT32BE putAway; /* Put away folder ID (i.e. if the user moves the - folder onto the desktop, the directory ID of - the folder from which the user moves it is - saved here) */ -}; - -/* - defines for FInfo & DInfo flags fields -*/ -enum -{ - fif_isOnDesk = 0x0001, /* System 6: set if item is located on desktop (files and folders) */ - /* System 7: Unused (set to 0) */ - fif_color = 0x000E, /* color coding (files and folders) */ - fif_colorReserved = 0x0010, /* System 6: reserved??? */ - /* System 7: Unused (set to 0) */ - fif_requiresSwitchLaunch= 0x0020, /* System 6: ??? */ - /* System 7: Unused (set to 0) */ - fif_isShared = 0x0040, /* Applications files: if set, the */ - /* application can be executed by */ - /* multiple users simultaneously. */ - /* Otherwise, set to 0. */ - fif_hasNoINITs = 0x0080, /* Extensions/Control Panels: if set(?), */ - /* this file contains no INIT */ - /* resource */ - /* Otherwise, set to 0. */ - fif_hasBeenInited = 0x0100, /* System 6: The Finder has recorded information from - the file???s bundle resource into the desktop - database and given the file or folder a - position on the desktop. */ - /* System 7? 8?: Clear if the file contains desktop database */ - /* resources ('BNDL', 'FREF', 'open', 'kind'...) */ - /* that have not been added yet. Set only by the Finder */ - /* Reserved for folders - make sure this bit is cleared for folders */ - - /* bit 0x0200 was at a point (AOCE for system 7.x?) the letter bit for - AOCE, but was reserved before and it is reserved again in recent MacOS - releases. */ - - fif_hasCustomIcon = 0x0400, /* (files and folders) */ - fif_isStationery = 0x0800, /* System 7: (files only) */ - fif_nameLocked = 0x1000, /* (files and folders) */ - fif_hasBundle = 0x2000, /* Files only */ - fif_isInvisible = 0x4000, /* (files and folders) */ - fif_isAlias = 0x8000 /* System 7: (files only) */ -}; - -/* - mac_to_c_strncpy() - - Encode a macintosh string as a C string. The NUL character is escaped, - using the "%00" sequence. To avoid any ambiguity, '%' is escaped with - '%25'. - - dst (O): C string - n (I): length of buffer pointed to by dst - src (I): macintosh string (first byte is length) -*/ -static void mac_to_c_strncpy(char *dst, int n, uint8_t *src) -{ - size_t len = src[0]; - int i, j; - - i = j = 0; - while ((i < len) && (j < n-1)) - { - switch (src[i+1]) - { - case '\0': - if (j >= n-3) - goto exit; - dst[j] = '%'; - dst[j+1] = '0'; - dst[j+2] = '0'; - j += 3; - break; - - case '%': - if (j >= n-3) - goto exit; - dst[j] = '%'; - dst[j+1] = '2'; - dst[j+2] = '5'; - j += 3; - break; - - default: - dst[j] = src[i+1]; - j++; - break; - } - i++; - } - -exit: - if (n > 0) - dst[j] = '\0'; -} - -/* - c_to_mac_strncpy() - - Decode a C string to a macintosh string. The NUL character is escaped, - using the "%00" sequence. To avoid any ambiguity, '%' is escaped with - '%25'. - - dst (O): macintosh string (first byte is length) - src (I): C string - n (I): length of string pointed to by src -*/ -static void c_to_mac_strncpy(mac_str255 dst, const char *src, int n) -{ - size_t len; - int i; - char buf[3]; - - - len = 0; - i = 0; - while ((i < n) && (len < 255)) - { - switch (src[i]) - { - case '%': - if (i >= n-2) - goto exit; - buf[0] = src[i+1]; - buf[1] = src[i+2]; - buf[2] = '\0'; - dst[len+1] = strtoul(buf, NULL, 16); - i += 3; - break; - - default: - dst[len+1] = src[i]; - i++; - break; - } - len++; - } - -exit: - dst[0] = len; -} - -/* - mac_strcmp() - - Compare two macintosh strings - - s1 (I): the string to compare - s2 (I): the comparison string - - Return a zero if s1 and s2 are equal, a negative value if s1 is less than - s2, and a positive value if s1 is greater than s2. -*/ -#ifdef UNUSED_FUNCTION -static int mac_strcmp(const uint8_t *s1, const uint8_t *s2) -{ - size_t common_len; - - common_len = (s1[0] <= s2[0]) ? s1[0] : s2[0]; - - return memcmp(s1+1, s2+1, common_len) || ((int)s1[0] - s2[0]); -} -#endif - -/* - mac_stricmp() - - Compare two macintosh strings in a manner compatible with the macintosh HFS - file system. - - This functions emulates the way HFS (and MFS???) sorts string: this is - equivalent to the RelString macintosh toolbox call with the caseSensitive - parameter as false and the diacSensitive parameter as true. - - s1 (I): the string to compare - s2 (I): the comparison string - - Return a zero if s1 and s2 are equal, a negative value if s1 is less than - s2, and a positive value if s1 is greater than s2. - -Known issues: - Using this function makes sense with the MacRoman encoding, as it means the - computer will regard "DeskTop File", "Desktop File", "Desktop file", etc, - as the same file. (UNIX users will probably regard this as an heresy, but - you must consider that, unlike UNIX, the Macintosh was not designed for - droids, but error-prone human beings that may forget about case.) - - (Also, letters with diatrical signs follow the corresponding letters - without diacritical signs in the HFS catalog file. This does not matter, - though, since the Finder will not display files in the HFS catalog order, - but it will instead sort files according to whatever order is currently - selected in the View menu.) - - However, with other text encodings, the behavior will be completely absurd. - For instance, with the Greek encoding, it will think that the degree symbol - is the same letter (with different case) as the upper-case Psi, so that if - a program asks for a file called "90??" on a greek HFS volume, and there is - a file called "90??" on this volume, file "90??" will be opened. - Results will probably be even weirder with 2-byte scripts like Japanese or - Chinese. Of course, we are not going to fix this issue, since doing so - would break the compatibility with the original Macintosh OS. -*/ - -static int mac_stricmp(const uint8_t *s1, const uint8_t *s2) -{ - static const unsigned char mac_char_sort_table[256] = - { - /* \x00 \x01 \x02 \x03 \x04 \x05 \x06 \x07 */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - /* \x08 \x09 \x0a \x0b \x0c \x0d \x0e \x0f */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - /* \x10 \x11 \x12 \x13 \x14 \x15 \x16 \x17 */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - /* \x18 \x19 \x1a \x1b \x1c \x1d \x1e \x1f */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - /* \x20 \x21 \x22 \x23 \x24 \x25 \x26 \x27 */ - 0x20, 0x21, 0x22, 0x27, 0x28, 0x29, 0x2a, 0x2b, - /* \x28 \x29 \x2a \x2b \x2c \x2d \x2e \x2f */ - 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, - /* \x30 \x31 \x32 \x33 \x34 \x35 \x36 \x37 */ - 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, - /* \x38 \x39 \x3a \x3b \x3c \x3d \x3e \x3f */ - 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, - /* \x40 \x41 \x42 \x43 \x44 \x45 \x46 \x47 */ - 0x46, 0x47, 0x51, 0x52, 0x54, 0x55, 0x5a, 0x5b, - /* \x48 \x49 \x4a \x4b \x4c \x4d \x4e \x4f */ - 0x5c, 0x5d, 0x62, 0x63, 0x64, 0x65, 0x66, 0x68, - /* \x50 \x51 \x52 \x53 \x54 \x55 \x56 \x57 */ - 0x71, 0x72, 0x73, 0x74, 0x76, 0x77, 0x7c, 0x7d, - /* \x58 \x59 \x5a \x5b \x5c \x5d \x5e \x5f */ - 0x7e, 0x7f, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, - /* \x60 \x61 \x62 \x63 \x64 \x65 \x66 \x67 */ - 0x4d, 0x47, 0x51, 0x52, 0x54, 0x55, 0x5a, 0x5b, - /* \x68 \x69 \x6a \x6b \x6c \x6d \x6e \x6f */ - 0x5c, 0x5d, 0x62, 0x63, 0x64, 0x65, 0x66, 0x68, - /* \x70 \x71 \x72 \x73 \x74 \x75 \x76 \x77 */ - 0x71, 0x72, 0x73, 0x74, 0x76, 0x77, 0x7c, 0x7d, - /* \x78 \x79 \x7a \x7b \x7c \x7d \x7e \x7f */ - 0x7e, 0x7f, 0x81, 0x87, 0x88, 0x89, 0x8a, 0x8b, - /* \x80 \x81 \x82 \x83 \x84 \x85 \x86 \x87 */ - 0x49, 0x4b, 0x53, 0x56, 0x67, 0x69, 0x78, 0x4e, - /* \x88 \x89 \x8a \x8b \x8c \x8d \x8e \x8f */ - 0x48, 0x4f, 0x49, 0x4a, 0x4b, 0x53, 0x56, 0x57, - /* \x90 \x91 \x92 \x93 \x94 \x95 \x96 \x97 */ - 0x58, 0x59, 0x5e, 0x5f, 0x60, 0x61, 0x67, 0x6d, - /* \x98 \x99 \x9a \x9b \x9c \x9d \x9e \x9f */ - 0x6e, 0x6f, 0x69, 0x6a, 0x79, 0x7a, 0x7b, 0x78, - /* \xa0 \xa1 \xa2 \xa3 \xa4 \xa5 \xa6 \xa7 */ - 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x75, - /* \xa8 \xa9 \xaa \xab \xac \xad \xae \xaf */ - 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x4c, 0x6b, - /* \xb0 \xb1 \xb2 \xb3 \xb4 \xb5 \xb6 \xb7 */ - 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, - /* \xb8 \xb9 \xba \xbb \xbc \xbd \xbe \xbf */ - 0xa1, 0xa2, 0xa3, 0x50, 0x70, 0xa4, 0x4c, 0x6b, - /* \xc0 \xc1 \xc2 \xc3 \xc4 \xc5 \xc6 \xc7 */ - 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0x25, - /* \xc8 \xc9 \xca \xcb \xcc \xcd \xce \xcf */ - 0x26, 0xac, 0x20, 0x48, 0x4a, 0x6a, 0x6c, 0x6c, - /* \xd0 \xd1 \xd2 \xd3 \xd4 \xd5 \xd6 \xd7 */ - 0xad, 0xae, 0x23, 0x24, 0x2c, 0x2d, 0xaf, 0xb0, - /* \xd8 \xd9 \xda \xdb \xdc \xdd \xde \xdf */ - 0x80, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, - /* \xe0 \xe1 \xe2 \xe3 \xe4 \xe5 \xe6 \xe7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, - /* \xe8 \xe9 \xea \xeb \xec \xed \xee \xef */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, - /* \xf0 \xf1 \xf2 \xf3 \xf4 \xf5 \xf6 \xf7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, - /* \xf8 \xf9 \xfa \xfb \xfc \xfd \xfe \xff */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7 - }; - - size_t common_len; - int i; - int c1, c2; - - common_len = (s1[0] <= s2[0]) ? s1[0] : s2[0]; - - for (i=0; i<common_len; i++) - { - c1 = mac_char_sort_table[s1[i+1]]; - c2 = mac_char_sort_table[s2[i+1]]; - if (c1 != c2) - return c1 - c2; - } - - return ((int)s1[0] - s2[0]); -} - -/* - mac_strcpy() - - Copy a macintosh string - - dst (O): dest macintosh string - src (I): source macintosh string (first byte is length) - - Return a zero if s1 and s2 are equal, a negative value if s1 is less than - s2, and a positive value if s1 is greater than s2. -*/ -static inline void mac_strcpy(uint8_t *dest, const uint8_t *src) -{ - memcpy(dest, src, src[0]+1); -} - -#ifdef UNUSED_FUNCTION -/* - mac_strncpy() - - Copy a macintosh string - - dst (O): dest macintosh string - n (I): max string length for dest (range 0-255, buffer length + 1) - src (I): source macintosh string (first byte is length) -*/ -static void mac_strncpy(uint8_t *dest, int n, const uint8_t *src) -{ - size_t len; - - len = src[0]; - if (len > n) - len = n; - dest[0] = len; - memcpy(dest+1, src+1, len); -} -#endif - -/* - disk image reference -*/ -struct mac_l1_imgref -{ - imgtool::image *image; - uint32_t heads; -}; - - - -static imgtoolerr_t mac_find_block(mac_l1_imgref *image, int block, - uint32_t *track, uint32_t *head, uint32_t *sector) -{ - *track = 0; - while(block >= (apple35_sectors_per_track(imgtool_floppy(*image->image), *track) * image->heads)) - { - block -= (apple35_sectors_per_track(imgtool_floppy(*image->image), (*track)++) * image->heads); - if (*track >= 80) - return IMGTOOLERR_SEEKERROR; - } - - *head = block / apple35_sectors_per_track(imgtool_floppy(*image->image), *track); - *sector = block % apple35_sectors_per_track(imgtool_floppy(*image->image), *track); - return IMGTOOLERR_SUCCESS; -} - - - -/* - image_read_block() - - Read one 512-byte block of data from a macintosh disk image - - image (I/O): level-1 image reference - block (I): address of block to read - dest (O): buffer where block data should be stored - - Return imgtool error code -*/ -static imgtoolerr_t image_read_block(mac_l1_imgref *image, uint32_t block, void *dest) -{ - imgtoolerr_t err; - floperr_t ferr; - uint32_t track, head, sector; - - err = mac_find_block(image, block, &track, &head, §or); - if (err) - return err; - - ferr = floppy_read_sector(imgtool_floppy(*image->image), head, track, sector, 0, dest, 512); - if (ferr) - return imgtool_floppy_error(ferr); - - return IMGTOOLERR_SUCCESS; -} - -/* - image_write_block() - - Read one 512-byte block of data from a macintosh disk image - - image (I/O): level-1 image reference - block (I): address of block to write - src (I): buffer with the block data - - Return imgtool error code -*/ -static imgtoolerr_t image_write_block(mac_l1_imgref *image, uint32_t block, const void *src) -{ - imgtoolerr_t err; - floperr_t ferr; - uint32_t track, head, sector; - - err = mac_find_block(image, block, &track, &head, §or); - if (err) - return err; - - ferr = floppy_write_sector(imgtool_floppy(*image->image), head, track, sector, 0, src, 512, 0); /* TODO: pass ddam argument from imgtool */ - if (ferr) - return imgtool_floppy_error(ferr); - - return IMGTOOLERR_SUCCESS; -} - -/* - image_get_tag_len() - - Get length of tag data (12 for GCR floppies, 20 for HD20, 0 otherwise) - - image (I/O): level-1 image reference - - Return tag length -*/ -static inline int image_get_tag_len(mac_l1_imgref *image) -{ - return 0; -} - - - -/* - image_read_tag() - - Read a 12- or 20-byte tag record associated with a disk block - - image (I/O): level-1 image reference - block (I): address of block to read - dest (O): buffer where tag data should be stored - - Return imgtool error code -*/ -static imgtoolerr_t image_read_tag(mac_l1_imgref *image, uint32_t block, void *dest) -{ - return IMGTOOLERR_UNEXPECTED; -} - -/* - image_write_tag() - - Write a 12- or 20-byte tag record associated with a disk block - - image (I/O): level-1 image reference - block (I): address of block to write - src (I): buffer with the tag data - - Return imgtool error code -*/ -static imgtoolerr_t image_write_tag(mac_l1_imgref *image, uint32_t block, const void *src) -{ - return IMGTOOLERR_UNEXPECTED; -} - -#if 0 -#pragma mark - -#pragma mark MFS/HFS WRAPPERS -#endif - -enum mac_format -{ - L2I_MFS, - L2I_HFS -}; - -enum mac_forkID { data_fork = 0x00, rsrc_fork = 0xff }; - -/* - MFS image ref -*/ -struct mfs_l2_imgref -{ - uint16_t dir_num_files; - uint16_t dir_start; - uint16_t dir_blk_len; - - uint16_t ABStart; - - mac_str27 volname; - - unsigned char ABlink_dirty[13]; /* dirty flag for each disk block in the ABlink array */ - uint8_t ABlink[6141]; -}; - -/* - HFS extent descriptor -*/ -struct hfs_extent -{ - UINT16BE stABN; /* first allocation block */ - UINT16BE numABlks; /* number of allocation blocks */ -}; - -/* - HFS likes to group extents by 3 (it is 8 with HFS+), so we create a - specific type. -*/ -typedef hfs_extent hfs_extent_3[3]; - -/* - MFS open file ref -*/ -struct mfs_fileref -{ - uint16_t stBlk; /* first allocation block of file */ -}; - -/* - HFS open file ref -*/ -struct hfs_fileref -{ - hfs_extent_3 extents; /* first 3 file extents */ - - uint32_t parID; /* CNID of parent directory (undefined for extent & catalog files) */ - mac_str31 filename; /* file name (undefined for extent & catalog files) */ -}; - -struct mac_l2_imgref; - -/* - MFS/HFS open file ref -*/ -struct mac_fileref -{ - struct mac_l2_imgref *l2_img; /* image pointer */ - - uint32_t fileID; /* file ID (a.k.a. CNID in HFS/HFS+) */ - - mac_forkID forkType; /* 0x00 for data, 0xff for resource */ - - uint32_t eof; /* logical end-of-file */ - uint32_t pLen; /* physical end-of-file */ - - uint32_t crPs; /* current position in file */ - - uint8_t reload_buf; - uint8_t block_buffer[512]; /* buffer with current file block */ - - union - { - mfs_fileref mfs; - hfs_fileref hfs; - }; -}; - -/* - open BT ref -*/ -struct mac_BTref -{ - struct mac_fileref fileref; /* open B-tree file ref */ - - uint16_t nodeSize; /* size of a node, in bytes */ - uint32_t rootNode; /* node number of root node */ - uint32_t firstLeafNode; /* node number of first leaf node */ - uint32_t attributes; /* persistent attributes about the tree */ - uint16_t treeDepth; /* maximum height (usually leaf nodes) */ - uint16_t maxKeyLength; /* maximum key length */ - - /* function to compare keys during tree searches */ - int (*key_compare_func)(const void *key1, const void *key2); - - void *node_buf; /* current node buffer */ -}; - -/* - Constants for BTHeaderRec attributes field -*/ -enum -{ - btha_badCloseMask = 0x00000001, /* reserved */ - btha_bigKeysMask = 0x00000002, /* key length field is 16 bits */ - btha_variableIndexKeysMask = 0x00000004 /* keys in index nodes are variable length */ -}; - -/* - HFS image ref -*/ -struct hfs_l2_imgref -{ - uint16_t VBM_start; - - uint16_t ABStart; - - mac_str27 volname; - - mac_BTref extents_BT; - mac_BTref cat_BT; - - uint8_t VBM[8192]; -}; - -/* - MFS/HFS image ref -*/ -struct mac_l2_imgref -{ - mac_l1_imgref l1_img; - - uint16_t numABs; - uint16_t blocksperAB; - - uint16_t freeABs; - - uint32_t nxtCNID; /* nxtFNum in MFS, nxtCNID in HFS */ - - mac_format format; - union - { - mfs_l2_imgref mfs; - hfs_l2_imgref hfs; - } u; -}; - -/* - MFS Master Directory Block -*/ -struct mfs_mdb -{ - uint8_t sigWord[2]; /* volume signature - always $D2D7 */ - UINT32BE crDate; /* date and time of volume creation */ - UINT32BE lsMod/*lsBkUp???*/;/* date and time of last modification (backup???) */ - UINT16BE atrb; /* volume attributes (0x0000) */ - /* bit 15 is set if volume is locked by software */ - UINT16BE nmFls; /* number of files in directory */ - UINT16BE dirSt; /* first block of directory */ - - UINT16BE blLn; /* length of directory in blocks (0x000C) */ - UINT16BE nmAlBlks; /* number of allocation blocks in volume (0x0187) */ - UINT32BE alBlkSiz; /* size (in bytes) of allocation blocks (0x00000400) */ - UINT32BE clpSiz; /* default clump size - number of bytes to allocate - when a file grows (0x00002000) */ - UINT16BE alBlSt; /* first allocation block in volume (0x0010) */ - - UINT32BE nxtFNum; /* next unused file number */ - UINT16BE freeABs; /* number of unused allocation blocks */ - - mac_str27 VN; /* volume name */ - - uint8_t ABlink[512-64];/* Link array for file ABs. Array of nmAlBlks - 12-bit-long entries, indexed by AB address. If an - AB belongs to no file, the entry is 0; if an AB is - the last in any file, the entry is 1; if an AB - belongs to a file and is not the last one, the - entry is the AB address of the next file AB plus 1. - Note that the array extends on as many consecutive - disk blocks as needed (usually the MDB block plus - the next one). Incidentally, this array is not - saved in the secondary MDB: presumably, the idea - was that the disk utility could rely on the tag - data to rebuild the link array if it should ever - be corrupted. */ -}; - -/* - HFS Master Directory Block -*/ -struct hfs_mdb -{ -/* First fields are similar to MFS, though several fields have a different meaning */ - uint8_t sigWord[2]; /* volume signature - always $D2D7 */ - UINT32BE crDate; /* date and time of volume creation */ - UINT32BE lsMod; /* date and time of last modification */ - UINT16BE atrb; /* volume attributes (0x0000) */ - /* bit 15 is set if volume is locked by software */ - UINT16BE nmFls; /* number of files in root folder */ - UINT16BE VBMSt; /* first block of volume bitmap */ - UINT16BE allocPtr; /* start of next allocation search */ - - UINT16BE nmAlBlks; /* number of allocation blocks in volume */ - UINT32BE alBlkSiz; /* size (in bytes) of allocation blocks */ - UINT32BE clpSiz; /* default clump size - number of bytes to allocate - when a file grows */ - UINT16BE alBlSt; /* first allocation block in volume (0x0010) */ - UINT32BE nxtCNID; /* next unused catalog node ID */ - UINT16BE freeABs; /* number of unused allocation blocks */ - mac_str27 VN; /* volume name */ - -/* next fields are HFS-specific */ - - UINT32BE volBkUp; /* date and time of last backup */ - UINT16BE vSeqNum; /* volume backup sequence number */ - UINT32BE wrCnt; /* volume write count */ - UINT32BE xtClpSiz; /* clump size for extents overflow file */ - UINT32BE ctClpSiz; /* clump size for catalog file */ - UINT16BE nmRtDirs; /* number of directories in root folder */ - UINT32BE filCnt; /* number of files in volume */ - UINT32BE dirCnt; /* number of directories in volume */ - uint8_t fndrInfo[32]; /* information used by the Finder */ - - union - { - struct - { - UINT16BE VCSize; /* size (in blocks) of volume cache */ - UINT16BE VBMCSize; /* size (in blocks) of volume bitmap cache */ - UINT16BE ctlCSize; /* size (in blocks) of common volume cache */ - }; - struct - { - UINT16BE embedSigWord; /* embedded volume signature */ - hfs_extent embedExtent; /* embedded volume location and size */ - } v2; - } u; - - UINT32BE xtFlSize; /* size (in bytes) of extents overflow file */ - hfs_extent_3 xtExtRec; /* extent record for extents overflow file */ - UINT32BE ctFlSize; /* size (in bytes) of catalog file */ - hfs_extent_3 ctExtRec; /* extent record for catalog file */ -}; - -/* to save a little stack space, we use the same buffer for MDB and next blocks */ -union img_open_buf -{ - struct mfs_mdb mfs_mdb; - struct hfs_mdb hfs_mdb; - uint8_t raw[512]; -}; - -/* - Information extracted from catalog/directory -*/ -struct mac_dirent -{ - uint16_t dataRecType; /* type of data record */ - - mac_FInfo flFinderInfo; /* information used by the Finder */ - mac_FXInfo flXFinderInfo; /* information used by the Finder */ - - uint8_t flags; /* bit 0=1 if file locked */ - - uint32_t fileID; /* file ID in directory/catalog */ - - uint32_t dataLogicalSize; /* logical EOF of data fork */ - uint32_t dataPhysicalSize; /* physical EOF of data fork */ - uint32_t rsrcLogicalSize; /* logical EOF of resource fork */ - uint32_t rsrcPhysicalSize; /* physical EOF of resource fork */ - - uint32_t createDate; /* date and time of creation */ - uint32_t modifyDate; /* date and time of last modification */ -}; - -/* - Tag record for GCR floppies (12 bytes) - - And, no, I don't know the format of the 20-byte tag record of the HD20 -*/ -struct floppy_tag_record -{ - UINT32BE fileID; /* a.k.a. CNID */ - /* a value of 1 seems to be the default for non-AB blocks, but this is not consistent */ - uint8_t ftype; /* bit 1 = 1 if resource fork */ - /* bit 0 = 1 if block is allocated to user file (i.e. it is not - in HFS extent & catalog, and not in non-AB blocks such - as MDB and MFS directory)??? */ - /* bit 7 seems to be used, but I don't know what it means */ - /* a value of $FF seems to be the default for non-AB blocks, but this is not consistent */ - uint8_t fattr; /* bit 0 = 1 if locked(?) */ - /* a value of $FF seems to be the default for non-AB blocks, but this is not consistent */ - UINT16BE fblock; /* relative file block number (enough for any volume up to 32 MBytes in size) */ - UINT32BE wrCnt; /* MFS: date and time of last write */ - /* HFS: seems related to the wrCnt field in the mdb, i.e. - each time a volume is written to, the current value of - wrCnt is written in the tag field, then it is incremented */ - /* (DV17 says "disk block number", but it cannot be true) */ -}; - -#ifdef UNUSED_FUNCTION -static void hfs_image_close(struct mac_l2_imgref *l2_img); -#endif -static imgtoolerr_t mfs_file_get_nth_block_address(struct mac_fileref *fileref, uint32_t block_num, uint32_t *block_address); -static imgtoolerr_t hfs_file_get_nth_block_address(struct mac_fileref *fileref, uint32_t block_num, uint32_t *block_address); -static imgtoolerr_t mfs_lookup_path(struct mac_l2_imgref *l2_img, const char *fpath, mac_str255 filename, mac_dirent *cat_info, int create_it); -static imgtoolerr_t hfs_lookup_path(struct mac_l2_imgref *l2_img, const char *fpath, uint32_t *parID, mac_str255 filename, mac_dirent *cat_info); -static imgtoolerr_t mfs_file_open(struct mac_l2_imgref *l2_img, const mac_str255 filename, mac_forkID fork, struct mac_fileref *fileref); -static imgtoolerr_t hfs_file_open(struct mac_l2_imgref *l2_img, uint32_t parID, const mac_str255 filename, mac_forkID fork, struct mac_fileref *fileref); -static imgtoolerr_t mfs_file_setABeof(struct mac_fileref *fileref, uint32_t newABeof); -static imgtoolerr_t mfs_dir_update(struct mac_fileref *fileref); - -static struct mac_l2_imgref *get_imgref(imgtool::image &img) -{ - return (struct mac_l2_imgref *) imgtool_floppy_extrabytes(img); -} - - -#ifdef UNUSED_FUNCTION -/* - mac_image_close - - Close a macintosh image. - - l2_img (I/O): level-2 image reference -*/ -static void mac_image_close(struct mac_l2_imgref *l2_img) -{ - switch (l2_img->format) - { - case L2I_MFS: - break; - - case L2I_HFS: - hfs_image_close(l2_img); - break; - } -} -#endif - -/* - mac_lookup_path - - Resolve a file path, and translate it to a parID + filename pair that enables - to do an efficient file search on a HFS volume (and an inefficient one on - MFS, but it is not an issue as MFS volumes typically have a few dozens - files, vs. possibly thousands with HFS volumes). - - l2_img (I/O): level-2 image reference - fpath (I): file path (C string) - parID (O): set to the CNID of the parent directory if the volume is in HFS - format (reserved for MFS volumes) - filename (O): set to the actual name of the file, with capitalization matching - the one on the volume rather than the one in the fpath parameter (Mac - string) - cat_info (O): catalog info for this file extracted from the catalog file - (may be NULL) - - Return imgtool error code -*/ -static imgtoolerr_t mac_lookup_path(struct mac_l2_imgref *l2_img, const char *fpath, uint32_t *parID, mac_str255 filename, mac_dirent *cat_info, int create_it) -{ - imgtoolerr_t err = IMGTOOLERR_UNEXPECTED; - - switch (l2_img->format) - { - case L2I_MFS: - *parID = 0; - err = mfs_lookup_path(l2_img, fpath, filename, cat_info, create_it); - break; - - case L2I_HFS: - err = hfs_lookup_path(l2_img, fpath, parID, filename, cat_info); - break; - } - return err; -} - -/* - mac_file_open - - Open a file located on a macintosh image - - l2_img (I/O): level-2 image reference - parID (I): CNID of the parent directory if the volume is in HFS format - (reserved for MFS volumes) - filename (I): name of the file (Mac string) - mac_forkID (I): tells which fork should be opened - fileref (O): mac file reference to open - - Return imgtool error code -*/ -static imgtoolerr_t mac_file_open(struct mac_l2_imgref *l2_img, uint32_t parID, const mac_str255 filename, mac_forkID fork, struct mac_fileref *fileref) -{ - switch (l2_img->format) - { - case L2I_MFS: - return mfs_file_open(l2_img, filename, fork, fileref); - - case L2I_HFS: - return hfs_file_open(l2_img, parID, filename, fork, fileref); - } - - return IMGTOOLERR_UNEXPECTED; -} - -/* - mac_file_read - - Read data from an open mac file, starting at current position in file - - fileref (I/O): mac file reference - len (I): number of bytes to read - dest (O): destination buffer - - Return imgtool error code -*/ -static imgtoolerr_t mac_file_read(struct mac_fileref *fileref, uint32_t len, void *dest) -{ - uint32_t block = 0; - floppy_tag_record tag; - int run_len; - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - - if ((fileref->crPs + len) > fileref->eof) - /* EOF */ - return IMGTOOLERR_UNEXPECTED; - - while (len > 0) - { - if (fileref->reload_buf) - { - switch (fileref->l2_img->format) - { - case L2I_MFS: - err = mfs_file_get_nth_block_address(fileref, fileref->crPs/512, &block); - break; - - case L2I_HFS: - err = hfs_file_get_nth_block_address(fileref, fileref->crPs/512, &block); - break; - } - if (err) - return err; - err = image_read_block(&fileref->l2_img->l1_img, block, fileref->block_buffer); - if (err) - return err; - fileref->reload_buf = false; - - if (TAG_EXTRA_CHECKS) - { - /* optional check */ - if (image_get_tag_len(&fileref->l2_img->l1_img) == 12) - { - err = image_read_tag(&fileref->l2_img->l1_img, block, &tag); - if (err) - return err; - - if ((get_UINT32BE(tag.fileID) != fileref->fileID) - || (((tag.ftype & 2) != 0) != (fileref->forkType == rsrc_fork)) - || (get_UINT16BE(tag.fblock) != ((fileref->crPs/512) & 0xffff))) - { - return IMGTOOLERR_CORRUPTIMAGE; - } - } - } - } - run_len = 512 - (fileref->crPs % 512); - if (run_len > len) - run_len = len; - - memcpy(dest, fileref->block_buffer+(fileref->crPs % 512), run_len); - len -= run_len; - dest = (uint8_t *)dest + run_len; - fileref->crPs += run_len; - if ((fileref->crPs % 512) == 0) - fileref->reload_buf = true; - } - - return IMGTOOLERR_SUCCESS; -} - -/* - mac_file_write - - Write data to an open mac file, starting at current position in file - - fileref (I/O): mac file reference - len (I): number of bytes to read - dest (O): destination buffer - - Return imgtool error code -*/ -static imgtoolerr_t mac_file_write(struct mac_fileref *fileref, uint32_t len, const void *src) -{ - uint32_t block = 0; - floppy_tag_record tag; - int run_len; - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - - if ((fileref->crPs + len) > fileref->eof) - /* EOF */ - return IMGTOOLERR_UNEXPECTED; - - while (len > 0) - { - switch (fileref->l2_img->format) - { - case L2I_MFS: - err = mfs_file_get_nth_block_address(fileref, fileref->crPs/512, &block); - break; - - case L2I_HFS: - err = hfs_file_get_nth_block_address(fileref, fileref->crPs/512, &block); - break; - } - if (err) - return err; - - if (TAG_CHECKS) - { - /* optional check */ - if (image_get_tag_len(&fileref->l2_img->l1_img) == 12) - { - err = image_read_tag(&fileref->l2_img->l1_img, block, &tag); - if (err) - return err; - - if ((get_UINT32BE(tag.fileID) != fileref->fileID) - || (((tag.ftype & 2) != 0) != (fileref->forkType == rsrc_fork)) - || (get_UINT16BE(tag.fblock) != ((fileref->crPs/512) & 0xffff))) - { - return IMGTOOLERR_CORRUPTIMAGE; - } - } - } - - if (fileref->reload_buf) - { - err = image_read_block(&fileref->l2_img->l1_img, block, fileref->block_buffer); - if (err) - return err; - fileref->reload_buf = false; - } - run_len = 512 - (fileref->crPs % 512); - if (run_len > len) - run_len = len; - - memcpy(fileref->block_buffer+(fileref->crPs % 512), src, run_len); - err = image_write_block(&fileref->l2_img->l1_img, block, fileref->block_buffer); - if (err) - return err; - /* update tag data */ - if (image_get_tag_len(&fileref->l2_img->l1_img) == 12) - { - if (!TAG_CHECKS) - { - err = image_read_tag(&fileref->l2_img->l1_img, block, &tag); - if (err) - return err; - } - - switch (fileref->l2_img->format) - { - case L2I_MFS: - set_UINT32BE(&tag.wrCnt, mac_time_now()); - break; - - case L2I_HFS: - /*set_UINT32BE(&tag.wrCnt, ++fileref->l2_img.u.hfs.wrCnt);*/ /* ***TODO*** */ - break; - } - - err = image_write_tag(&fileref->l2_img->l1_img, block, &tag); - if (err) - return err; - } - len -= run_len; - src = (const uint8_t *)src + run_len; - fileref->crPs += run_len; - if ((fileref->crPs % 512) == 0) - fileref->reload_buf = true; - } - - return IMGTOOLERR_SUCCESS; -} - -#ifdef UNUSED_FUNCTION -/* - mac_file_tell - - Get current position in an open mac file - - fileref (I/O): mac file reference - filePos (O): current position in file - - Return imgtool error code -*/ -static imgtoolerr_t mac_file_tell(struct mac_fileref *fileref, uint32_t *filePos) -{ - *filePos = fileref->crPs; - - return IMGTOOLERR_SUCCESS; -} -#endif - -/* - mac_file_seek - - Set current position in an open mac file - - fileref (I/O): mac file reference - filePos (I): new position in file - - Return imgtool error code -*/ -static imgtoolerr_t mac_file_seek(struct mac_fileref *fileref, uint32_t filePos) -{ - if ((fileref->crPs / 512) != (filePos / 512)) - fileref->reload_buf = true; - - fileref->crPs = filePos; - - return IMGTOOLERR_SUCCESS; -} - -/* - mac_file_seteof - - Set the position of the EOF in an open mac file - - fileref (I/O): mac file reference - newEof (I): new position of EOF in file - - Return imgtool error code -*/ -static imgtoolerr_t mac_file_seteof(struct mac_fileref *fileref, uint32_t newEof) -{ - uint32_t newABEof; - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - - newABEof = (newEof + fileref->l2_img->blocksperAB * 512 - 1) / (fileref->l2_img->blocksperAB * 512); - -#if 0 - if (fileref->pLen % (fileref->l2_img->blocksperAB * 512)) - return IMGTOOLERR_CORRUPTIMAGE; -#endif - - if (newEof < fileref->eof) - fileref->eof = newEof; - - switch (fileref->l2_img->format) - { - case L2I_MFS: - err = mfs_file_setABeof(fileref, newABEof); - break; - - case L2I_HFS: - err = IMGTOOLERR_UNIMPLEMENTED; - break; - } - if (err) - return err; - - fileref->eof = newEof; - - err = mfs_dir_update(fileref); - if (err) - return err; - - /* update current pos if beyond new EOF */ -#if 0 - if (fileref->crPs > newEof) - { - if ((fileref->crPs / 512) != (newEof / 512)) - fileref->reload_buf = true; - - fileref->crPs = newEof; - } -#endif - - return IMGTOOLERR_SUCCESS; -} - -#if 0 -#pragma mark - -#pragma mark MFS IMPLEMENTATION -#endif - -/* - directory entry for use in the directory file - - Note the structure is variable length. It is always word-aligned, and - cannot cross block boundaries. - - Note that the directory does not seem to be sorted: the order in which - files appear does not match file names, and it does not always match file - IDs. -*/ -struct mfs_dir_entry -{ - uint8_t flags; /* bit 7=1 if entry used, bit 0=1 if file locked */ - /* 0x00 means end of block: if we are not done - with reading the directory, the remnants will - be read from next block */ - uint8_t flVersNum; /* version number (usually 0x00, but I don't - have the IM volume that describes it) */ - mac_FInfo flFinderInfo; /* information used by the Finder */ - - UINT32BE fileID; /* file ID */ - - UINT16BE dataStartBlock; /* first allocation block of data fork */ - UINT32BE dataLogicalSize; /* logical EOF of data fork */ - UINT32BE dataPhysicalSize; /* physical EOF of data fork */ - UINT16BE rsrcStartBlock; /* first allocation block of resource fork */ - UINT32BE rsrcLogicalSize; /* logical EOF of resource fork */ - UINT32BE rsrcPhysicalSize; /* physical EOF of resource fork */ - - UINT32BE createDate; /* date and time of creation */ - UINT32BE modifyDate; /* date and time of last modification */ - - uint8_t name[1]; /* first char is length of file name */ - /* next chars are file name - 255 chars at most */ - /* IIRC, Finder 7 only supports 31 chars, - wheareas earlier versions support 63 chars */ -}; - -/* - FOBJ desktop resource: describes a folder, or the location of the volume - icon. - - In typical Apple manner, this resource is not documented. However, I have - managed to reverse engineer some parts of it. -*/ -struct mfs_FOBJ -{ - uint8_t unknown0[2]; /* $00: $0004 for disk, $0008 for folder??? */ - mac_point location; /* $02: location in parent window */ - uint8_t unknown1[4]; /* $06: ??? */ - uint8_t view; /* $0A: manner in which folders are displayed??? */ - uint8_t unknown2; /* $0B: ??? */ - UINT16BE par_fldr; /* $0C: parent folder ID */ - uint8_t unknown3[10]; /* $0E: ??? */ - UINT16BE unknown4; /* $18: ??? */ - UINT32BE createDate; /* $1A: date and time of creation */ - UINT32BE modifyDate; /* $1E: date and time of last modification */ - UINT16BE unknown5; /* $22: put-away folder ID?????? */ - uint8_t unknown6[8]; /* $24: ??? */ - mac_rect bounds; /* $2C: window bounds */ - mac_point scroll; /* $34: current scroll offset??? */ - union - { /* I think there are two versions of the structure */ - struct - { - UINT16BE item_count; /* number of items (folders and files) in - this folder */ - UINT32BE item_descs[1]; /* this variable-length array has - item_count entries - meaning of entry is unknown */ - } v1; - struct - { - UINT16BE zerofill; /* always 0? */ - UINT16BE unknown0; /* always 0??? */ - UINT16BE item_count; /* number of items (folders and files) in - this folder */ - uint8_t unknown1[20]; /* ??? */ - uint8_t name[1]; /* variable-length macintosh string */ - } v2; - } u; -}; - -/* - MFS open dir ref -*/ -struct mfs_dirref -{ - struct mac_l2_imgref *l2_img; /* image pointer */ - uint16_t index; /* current file index in the disk directory */ - uint16_t cur_block; /* current block offset in directory file */ - uint16_t cur_offset; /* current byte offset in current block of directory file */ - uint8_t block_buffer[512]; /* buffer with current directory block */ -}; - - - -static imgtoolerr_t mfs_image_create(imgtool::image &image, imgtool::stream::ptr &&dummy, util::option_resolution *opts) -{ - imgtoolerr_t err; - uint8_t buffer[512]; - uint32_t heads, tracks, sector_bytes, i; - uint32_t total_disk_blocks, total_allocation_blocks, allocation_block_size; - uint32_t free_allocation_blocks; - - heads = opts->lookup_int('H'); - tracks = opts->lookup_int('T'); - sector_bytes = opts->lookup_int('L'); - - get_imgref(image)->l1_img.image = ℑ - get_imgref(image)->l1_img.heads = heads; - - if (sector_bytes != 512) - return IMGTOOLERR_UNEXPECTED; - - /* computation */ - allocation_block_size = 1024; - total_disk_blocks = 0; - for (i = 0; i < tracks; i++) - total_disk_blocks += heads * apple35_sectors_per_track(imgtool_floppy(image), i) * sector_bytes / 512; - total_allocation_blocks = total_disk_blocks / (allocation_block_size / 512); - free_allocation_blocks = total_allocation_blocks - 3; - - /* write master directory block */ - memset(buffer, 0, sizeof(buffer)); - place_integer_be(buffer, 0, 2, 0xd2d7); /* signature */ - place_integer_be(buffer, 2, 4, mac_time_now()); /* creation date */ - place_integer_be(buffer, 6, 4, mac_time_now()); /* last modified date */ - place_integer_be(buffer, 10, 2, 0); /* volume attributes */ - place_integer_be(buffer, 12, 2, 0); /* number of files in directory */ - place_integer_be(buffer, 14, 2, 4); /* first block of directory */ - place_integer_be(buffer, 16, 2, 12); /* length of directory in blocks */ - place_integer_be(buffer, 18, 2, total_allocation_blocks); /* allocation blocks on volume count */ - place_integer_be(buffer, 20, 4, allocation_block_size); /* allocation block size */ - place_integer_be(buffer, 24, 4, 8192); /* default clumping size */ - place_integer_be(buffer, 28, 2, 16); /* first allocation block on volume */ - place_integer_be(buffer, 30, 4, 2); /* next unused catalog node */ - place_integer_be(buffer, 34, 2, free_allocation_blocks); /* free allocation block count */ - pascal_from_c_string(&buffer[36], 28, "Untitled"); /* volume title */ - - err = image_write_block(&get_imgref(image)->l1_img, 2, buffer); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - - -/* - mfs_image_open - - Open a MFS image. Image must already be open on level 1. This function - should not be called directly: call mac_image_open() instead. - - l2_img (I/O): level-2 image reference to open (l1_img and format fields - must be initialized) - img_open_buf (I): buffer with the MDB block - - Return imgtool error code -*/ -static imgtoolerr_t mfs_image_open(imgtool::image &image, imgtool::stream::ptr &&dummy) -{ - imgtoolerr_t err; - struct mac_l2_imgref *l2_img; - img_open_buf buf_local; - img_open_buf *buf; - - l2_img = get_imgref(image); - l2_img->l1_img.image = ℑ - l2_img->l1_img.heads = 1; - l2_img->format = L2I_MFS; - - /* read MDB */ - err = image_read_block(&l2_img->l1_img, 2, &buf_local.raw); - if (err) - return err; - buf = &buf_local; - - /* check signature word */ - if ((buf->mfs_mdb.sigWord[0] != 0xd2) || (buf->mfs_mdb.sigWord[1] != 0xd7) - || (buf->mfs_mdb.VN[0] > 27)) - return IMGTOOLERR_CORRUPTIMAGE; - - l2_img->u.mfs.dir_num_files = get_UINT16BE(buf->mfs_mdb.nmFls); - l2_img->u.mfs.dir_start = get_UINT16BE(buf->mfs_mdb.dirSt); - l2_img->u.mfs.dir_blk_len = get_UINT16BE(buf->mfs_mdb.blLn); - - l2_img->numABs = get_UINT16BE(buf->mfs_mdb.nmAlBlks); - if ((get_UINT32BE(buf->mfs_mdb.alBlkSiz) % 512) || (get_UINT32BE(buf->mfs_mdb.alBlkSiz) == 0)) - return IMGTOOLERR_CORRUPTIMAGE; - l2_img->blocksperAB = get_UINT32BE(buf->mfs_mdb.alBlkSiz) / 512; - l2_img->u.mfs.ABStart = get_UINT16BE(buf->mfs_mdb.alBlSt); - - l2_img->nxtCNID = get_UINT32BE(buf->mfs_mdb.nxtFNum); - - l2_img->freeABs = get_UINT16BE(buf->mfs_mdb.freeABs); - - mac_strcpy(l2_img->u.mfs.volname, buf->mfs_mdb.VN); - - if (l2_img->numABs > 4094) - return IMGTOOLERR_CORRUPTIMAGE; - - /* extract link array */ - { - int byte_len = l2_img->numABs + ((l2_img->numABs + 1) >> 1); - int cur_byte; - int cur_block; - int block_len = sizeof(buf->mfs_mdb.ABlink); - - /* clear dirty flags */ - for (cur_block=0; cur_block<13; cur_block++) - l2_img->u.mfs.ABlink_dirty[cur_block] = 0; - - /* append the chunk after MDB to link array */ - cur_byte = 0; - if (block_len > (byte_len - cur_byte)) - block_len = byte_len - cur_byte; - memcpy(l2_img->u.mfs.ABlink+cur_byte, buf->mfs_mdb.ABlink, block_len); - cur_byte += block_len; - cur_block = 2; - while (cur_byte < byte_len) - { - /* read next block */ - cur_block++; - err = image_read_block(&l2_img->l1_img, cur_block, buf->raw); - if (err) - return err; - block_len = 512; - - /* append this block to link array */ - if (block_len > (byte_len - cur_byte)) - block_len = byte_len - cur_byte; - memcpy(l2_img->u.mfs.ABlink+cur_byte, buf->raw, block_len); - cur_byte += block_len; - } - /* check that link array and directory don't overlap */ - if (cur_block >= l2_img->u.mfs.dir_start) - return IMGTOOLERR_CORRUPTIMAGE; - } - - return IMGTOOLERR_SUCCESS; -} - -/* - mfs_update_mdb - - Update MDB on disk - - l2_img (I/O): level-2 image reference - - Return imgtool error code -*/ -static imgtoolerr_t mfs_update_mdb(struct mac_l2_imgref *l2_img) -{ - imgtoolerr_t err; - union - { - struct mfs_mdb mfs_mdb; - uint8_t raw[512]; - } buf; - - assert(l2_img->format == L2I_MFS); - - /* read MDB */ - err = image_read_block(&l2_img->l1_img, 2, &buf.mfs_mdb); - if (err) - return err; - - set_UINT16BE(&buf.mfs_mdb.nmFls, l2_img->u.mfs.dir_num_files); -#if 0 /* these fields are never changed */ - set_UINT16BE(&buf.mfs_mdb.dirSt, l2_img->u.mfs.dir_start); - set_UINT16BE(&buf.mfs_mdb.blLn, l2_img->u.mfs.dir_blk_len); - - set_UINT16BE(&buf.mfs_mdb.nmAlBlks, l2_img->numABs); - set_UINT32BE(&buf.mfs_mdb.alBlkSiz, l2_img->blocksperAB*512); - set_UINT16BE(&buf.mfs_mdb.alBlSt, l2_img->u.mfs.ABStart); -#endif - - set_UINT32BE(&buf.mfs_mdb.nxtFNum, l2_img->nxtCNID); - - set_UINT16BE(&buf.mfs_mdb.freeABs, l2_img->freeABs); - -#if 0 /* these fields are never changed */ - mac_strcpy(buf.mfs_mdb.VN, l2_img->u.mfs.volname); -#endif - - /* save link array */ - { - int byte_len = l2_img->numABs + ((l2_img->numABs + 1) >> 1); - int cur_byte = 0; - int cur_block = 2; - int block_len = sizeof(buf.mfs_mdb.ABlink); - - /* update the chunk of link array after the MDB */ - if (block_len > (byte_len - cur_byte)) - block_len = byte_len - cur_byte; - memcpy(buf.mfs_mdb.ABlink, l2_img->u.mfs.ABlink+cur_byte, block_len); - cur_byte += block_len; - - if (block_len < sizeof(buf.mfs_mdb.ABlink)) - memset(buf.mfs_mdb.ABlink+block_len, 0, sizeof(buf.mfs_mdb.ABlink)-block_len); - - l2_img->u.mfs.ABlink_dirty[0] = 0; - - /* write back modified MDB+link */ - err = image_write_block(&l2_img->l1_img, 2, &buf.mfs_mdb); - if (err) - return err; - - while (cur_byte < byte_len) - { - /* advance to next block */ - cur_block++; - block_len = 512; - - /* extract the current chunk of link array */ - if (block_len > (byte_len - cur_byte)) - block_len = byte_len - cur_byte; - - if (l2_img->u.mfs.ABlink_dirty[cur_block-2]) - { - memcpy(buf.raw, l2_img->u.mfs.ABlink+cur_byte, block_len); - if (block_len < 512) - memset(buf.raw+block_len, 0, 512-block_len); - /* write back link array */ - err = image_write_block(&l2_img->l1_img, cur_block, buf.raw); - if (err) - return err; - l2_img->u.mfs.ABlink_dirty[cur_block-2] = 0; - } - - cur_byte += block_len; - } - } - - return IMGTOOLERR_SUCCESS; -} - -/* - mfs_dir_open - - Open the directory file - - l2_img (I/O): level-2 image reference - dirref (O): open directory file reference - - Return imgtool error code -*/ -static imgtoolerr_t mfs_dir_open(struct mac_l2_imgref *l2_img, const char *path, mfs_dirref *dirref) -{ - imgtoolerr_t err; - - assert(l2_img->format == L2I_MFS); - - if (path[0]) - return IMGTOOLERR_PATHNOTFOUND; - - dirref->l2_img = l2_img; - dirref->index = 0; - - dirref->cur_block = 0; - dirref->cur_offset = 0; - err = image_read_block(&l2_img->l1_img, l2_img->u.mfs.dir_start + dirref->cur_block, dirref->block_buffer); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - -/* - mfs_dir_read - - Read one entry of directory file - - dirref (I/O): open directory file reference - dir_entry (O): set to point to the entry read: set to NULL if EOF or error - - Return imgtool error code -*/ -static imgtoolerr_t mfs_dir_read(mfs_dirref *dirref, mfs_dir_entry **dir_entry) -{ - mfs_dir_entry *cur_dir_entry; - size_t cur_dir_entry_len; - imgtoolerr_t err; - - - if (dir_entry) - *dir_entry = NULL; - - if (dirref->index == dirref->l2_img->u.mfs.dir_num_files) - /* EOF */ - return IMGTOOLERR_SUCCESS; - - /* get cat entry pointer */ - cur_dir_entry = (mfs_dir_entry *) (dirref->block_buffer + dirref->cur_offset); - while ((dirref->cur_offset == 512) || ! (cur_dir_entry->flags & 0x80)) - { - dirref->cur_block++; - dirref->cur_offset = 0; - if (dirref->cur_block > dirref->l2_img->u.mfs.dir_blk_len) - /* aargh! */ - return IMGTOOLERR_CORRUPTIMAGE; - err = image_read_block(&dirref->l2_img->l1_img, dirref->l2_img->u.mfs.dir_start + dirref->cur_block, dirref->block_buffer); - if (err) - return err; - cur_dir_entry = (mfs_dir_entry *) (dirref->block_buffer + dirref->cur_offset); - } - - cur_dir_entry_len = offsetof(mfs_dir_entry, name) + cur_dir_entry->name[0] + 1; - - if ((dirref->cur_offset + cur_dir_entry_len) > 512) - /* aargh! */ - return IMGTOOLERR_CORRUPTIMAGE; - - /* entry looks valid: set pointer to entry */ - if (dir_entry) - *dir_entry = cur_dir_entry; - - /* update offset in block */ - dirref->cur_offset += cur_dir_entry_len; - /* align to word boundary */ - dirref->cur_offset = (dirref->cur_offset + 1) & ~1; - - /* update file count */ - dirref->index++; - - return IMGTOOLERR_SUCCESS; -} - -/* - mfs_dir_insert - - Add an entry in the directory file - - l2_img (I/O): level-2 image reference - dirref (I/O): open directory file reference - filename (I): name of the file for which an entry is created (Mac string) - dir_entry (O): set to point to the created entry: set to NULL if EOF or - error - - Return imgtool error code -*/ -static imgtoolerr_t mfs_dir_insert(struct mac_l2_imgref *l2_img, mfs_dirref *dirref, const uint8_t *new_fname, mfs_dir_entry **dir_entry) -{ - size_t new_dir_entry_len; - mfs_dir_entry *cur_dir_entry; - size_t cur_dir_entry_len; - uint32_t cur_date; - imgtoolerr_t err; - - dirref->l2_img = l2_img; - dirref->index = 0; - - new_dir_entry_len = offsetof(mfs_dir_entry, name) + new_fname[0] + 1; - - for (dirref->cur_block = 0; dirref->cur_block < dirref->l2_img->u.mfs.dir_blk_len; dirref->cur_block++) - { - /* read current block */ - err = image_read_block(&dirref->l2_img->l1_img, dirref->l2_img->u.mfs.dir_start + dirref->cur_block, dirref->block_buffer); - if (err) - return err; - - /* get free chunk in this block */ - dirref->cur_offset = 0; - cur_dir_entry = (mfs_dir_entry *) (dirref->block_buffer + dirref->cur_offset); - while ((dirref->cur_offset < 512) && (cur_dir_entry->flags & 0x80)) - { /* skip cur_dir_entry */ - cur_dir_entry_len = offsetof(mfs_dir_entry, name) + cur_dir_entry->name[0] + 1; - /* update offset in block */ - dirref->cur_offset += cur_dir_entry_len; - /* align to word boundary */ - dirref->cur_offset = (dirref->cur_offset + 1) & ~1; - /* update entry pointer */ - cur_dir_entry = (mfs_dir_entry *) (dirref->block_buffer + dirref->cur_offset); - /* update file index (useless, but can't harm) */ - dirref->index++; - } - - if (new_dir_entry_len <= (/*512*/510 - dirref->cur_offset)) - { - /*memcpy(cur_dir_entry, new_dir_entry, new_dir_entry_len);*/ - cur_dir_entry->flags = 0x80; - cur_dir_entry->flVersNum = 0x00; - memset(&cur_dir_entry->flFinderInfo, 0, sizeof(cur_dir_entry->flFinderInfo)); - set_UINT32BE(&cur_dir_entry->fileID, dirref->l2_img->nxtCNID++); - set_UINT16BE(&cur_dir_entry->dataStartBlock, 1); - set_UINT32BE(&cur_dir_entry->dataLogicalSize, 0); - set_UINT32BE(&cur_dir_entry->dataPhysicalSize, 0); - set_UINT16BE(&cur_dir_entry->rsrcStartBlock, 1); - set_UINT32BE(&cur_dir_entry->rsrcLogicalSize, 0); - set_UINT32BE(&cur_dir_entry->rsrcPhysicalSize, 0); - cur_date = mac_time_now(); - set_UINT32BE(&cur_dir_entry->createDate, cur_date); - set_UINT32BE(&cur_dir_entry->modifyDate, cur_date); - mac_strcpy(cur_dir_entry->name, new_fname); - - /* update offset in block */ - dirref->cur_offset += new_dir_entry_len; - /* align to word boundary */ - dirref->cur_offset = (dirref->cur_offset + 1) & ~1; - if (dirref->cur_offset < 512) - /* mark remaining space as free record */ - dirref->block_buffer[dirref->cur_offset] = 0; - /* write back directory */ - err = image_write_block(&dirref->l2_img->l1_img, dirref->l2_img->u.mfs.dir_start + dirref->cur_block, dirref->block_buffer); - if (err) - return err; - /* update file count */ - dirref->l2_img->u.mfs.dir_num_files++; - - /* update MDB (nxtCNID & dir_num_files fields) */ - err = mfs_update_mdb(dirref->l2_img); - if (err) - return err; - - if (dir_entry) - *dir_entry = cur_dir_entry; - return IMGTOOLERR_SUCCESS; - } - } - - return IMGTOOLERR_NOSPACE; -} - -/* - mfs_dir_update - - Update one entry of directory file - - fileref (I/O): open file reference - - Return imgtool error code -*/ -static imgtoolerr_t mfs_dir_update(struct mac_fileref *fileref) -{ - uint16_t cur_block; - uint16_t cur_offset; - uint8_t block_buffer[512]; - mfs_dir_entry *cur_dir_entry; - size_t cur_dir_entry_len; - imgtoolerr_t err; - - for (cur_block = 0; cur_block < fileref->l2_img->u.mfs.dir_blk_len; cur_block++) - { - /* read current block */ - err = image_read_block(&fileref->l2_img->l1_img, fileref->l2_img->u.mfs.dir_start + cur_block, block_buffer); - if (err) - return err; - - /* get free chunk in this block */ - cur_offset = 0; - cur_dir_entry = (mfs_dir_entry *) (block_buffer + cur_offset); - while ((cur_offset < 512) && (cur_dir_entry->flags & 0x80)) - { - if (get_UINT32BE(cur_dir_entry->fileID) == fileref->fileID) - { /* found it: update directory entry */ - switch (fileref->forkType) - { - case data_fork: - set_UINT16BE(&cur_dir_entry->dataStartBlock, fileref->mfs.stBlk); - set_UINT32BE(&cur_dir_entry->dataLogicalSize, fileref->eof); - set_UINT32BE(&cur_dir_entry->dataPhysicalSize, fileref->pLen); - break; - - case rsrc_fork: - set_UINT16BE(&cur_dir_entry->rsrcStartBlock, fileref->mfs.stBlk); - set_UINT32BE(&cur_dir_entry->rsrcLogicalSize, fileref->eof); - set_UINT32BE(&cur_dir_entry->rsrcPhysicalSize, fileref->pLen); - break; - } - /* write back directory */ - err = image_write_block(&fileref->l2_img->l1_img, fileref->l2_img->u.mfs.dir_start + cur_block, block_buffer); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; - } - /* skip cur_dir_entry */ - cur_dir_entry_len = offsetof(mfs_dir_entry, name) + cur_dir_entry->name[0] + 1; - /* update offset in block */ - cur_offset += cur_dir_entry_len; - /* align to word boundary */ - cur_offset = (cur_offset + 1) & ~1; - /* update entry pointer */ - cur_dir_entry = (mfs_dir_entry *) (block_buffer + cur_offset); - } - } - - return IMGTOOLERR_UNEXPECTED; -} - - -/* - mfs_find_dir_entry - - Find a file in an MFS directory - - dirref (I/O): open directory file reference - filename (I): file name (Mac string) - dir_entry (O): set to point to the entry read: set to NULL if EOF or error - - Return imgtool error code -*/ -static imgtoolerr_t mfs_find_dir_entry(mfs_dirref *dirref, const mac_str255 filename, mfs_dir_entry **dir_entry) -{ - mfs_dir_entry *cur_dir_entry; - imgtoolerr_t err; - - if (dir_entry) - *dir_entry = NULL; - - /* scan dir for file */ - while (1) - { - err = mfs_dir_read(dirref, &cur_dir_entry); - if (err) - return err; - if (!cur_dir_entry) - /* EOF */ - break; - if ((! mac_stricmp(filename, cur_dir_entry->name)) && (cur_dir_entry->flVersNum == 0)) - { /* file found */ - - if (dir_entry) - *dir_entry = cur_dir_entry; - - return IMGTOOLERR_SUCCESS; - } - } - - return IMGTOOLERR_FILENOTFOUND; -} - -/* - mfs_lookup_path - - Resolve a file path for MFS volumes. This function should not be called - directly: call mac_lookup_path instead. - - l2_img (I/O): level-2 image reference - fpath (I): file path (C string) - filename (O): set to the actual name of the file, with capitalization matching - the one on the volume rather than the one in the fpath parameter (Mac - string) - cat_info (I/O): on output, catalog info for this file extracted from the - catalog file (may be NULL) - If create_it is true, created info will first be set according to the - data from cat_info - create_it (I): true if entry should be created if not found - - Return imgtool error code -*/ -static imgtoolerr_t mfs_lookup_path(struct mac_l2_imgref *l2_img, const char *fpath, mac_str255 filename, mac_dirent *cat_info, int create_it) -{ - mfs_dirref dirref; - mfs_dir_entry *dir_entry; - imgtoolerr_t err; - - /* rapid check */ - if (strchr(fpath, ':')) - return IMGTOOLERR_BADFILENAME; - - /* extract file name */ - c_to_mac_strncpy(filename, fpath, strlen(fpath)); - - /* open dir */ - mfs_dir_open(l2_img, "", &dirref); - - /* find file */ - err = mfs_find_dir_entry(&dirref, filename, &dir_entry); - if ((err == IMGTOOLERR_FILENOTFOUND) && create_it) - err = mfs_dir_insert(l2_img, &dirref, filename, &dir_entry); - if (err) - return err; - - mac_strcpy(filename, dir_entry->name); - - if (create_it && cat_info) - { - dir_entry->flFinderInfo = cat_info->flFinderInfo; - dir_entry->flags = (dir_entry->flags & 0x80) | (cat_info->flags & 0x7f); - set_UINT32BE(&dir_entry->createDate, cat_info->createDate); - set_UINT32BE(&dir_entry->modifyDate, cat_info->modifyDate); - - /* write current directory block */ - err = image_write_block(&l2_img->l1_img, l2_img->u.mfs.dir_start + dirref.cur_block, dirref.block_buffer); - if (err) - return err; - } - - if (cat_info) - { - cat_info->flFinderInfo = dir_entry->flFinderInfo; - memset(&cat_info->flXFinderInfo, 0, sizeof(cat_info->flXFinderInfo)); - cat_info->flags = dir_entry->flags; - cat_info->fileID = get_UINT32BE(dir_entry->fileID); - cat_info->dataLogicalSize = get_UINT32BE(dir_entry->dataLogicalSize); - cat_info->dataPhysicalSize = get_UINT32BE(dir_entry->dataPhysicalSize); - cat_info->rsrcLogicalSize = get_UINT32BE(dir_entry->rsrcLogicalSize); - cat_info->rsrcPhysicalSize = get_UINT32BE(dir_entry->rsrcPhysicalSize); - cat_info->createDate = get_UINT32BE(dir_entry->createDate); - cat_info->modifyDate = get_UINT32BE(dir_entry->modifyDate); - cat_info->dataRecType = 0x200; /* hcrt_File */ - } - - return IMGTOOLERR_SUCCESS; -} - -/* - mfs_file_open_internal - - Open a file fork, given its directory entry. This function should not be - called directly: call mfs_file_open instead. - - l2_img (I/O): level-2 image reference - dir_entry (I): directory entry for the file to open - mac_forkID (I): tells which fork should be opened - fileref (O): mac file reference to open - - Return imgtool error code -*/ -static imgtoolerr_t mfs_file_open_internal(struct mac_l2_imgref *l2_img, const mfs_dir_entry *dir_entry, mac_forkID fork, struct mac_fileref *fileref) -{ - assert(l2_img->format == L2I_MFS); - - fileref->l2_img = l2_img; - - fileref->fileID = get_UINT32BE(dir_entry->fileID); - fileref->forkType = fork; - - switch (fork) - { - case data_fork: - fileref->mfs.stBlk = get_UINT16BE(dir_entry->dataStartBlock); - fileref->eof = get_UINT32BE(dir_entry->dataLogicalSize); - fileref->pLen = get_UINT32BE(dir_entry->dataPhysicalSize); - break; - - case rsrc_fork: - fileref->mfs.stBlk = get_UINT16BE(dir_entry->rsrcStartBlock); - fileref->eof = get_UINT32BE(dir_entry->rsrcLogicalSize); - fileref->pLen = get_UINT32BE(dir_entry->rsrcPhysicalSize); - break; - } - - fileref->crPs = 0; - - fileref->reload_buf = true; - - return IMGTOOLERR_SUCCESS; -} - -/* - mfs_file_open - - Open a file located on a MFS volume. This function should not be called - directly: call mac_file_open instead. - - l2_img (I/O): level-2 image reference - filename (I): name of the file (Mac string) - mac_forkID (I): tells which fork should be opened - fileref (O): mac file reference to open - - Return imgtool error code -*/ -static imgtoolerr_t mfs_file_open(struct mac_l2_imgref *l2_img, const mac_str255 filename, mac_forkID fork, struct mac_fileref *fileref) -{ - mfs_dirref dirref; - mfs_dir_entry *dir_entry; - imgtoolerr_t err; - - /* open dir */ - mfs_dir_open(l2_img, "", &dirref); - - /* find file */ - err = mfs_find_dir_entry(&dirref, filename, &dir_entry); - if (err) - return err; - - /* open it */ - return mfs_file_open_internal(l2_img, dir_entry, fork, fileref); -} - -/* - mfs_get_ABlink - - Read one entry of the Allocation Bitmap link array, on an MFS volume. - - l2_img (I/O): level-2 image reference - AB_address (I): index in the array, which is an AB address - - Returns the 12-bit value read in array. -*/ -static uint16_t mfs_get_ABlink(struct mac_l2_imgref *l2_img, uint16_t AB_address) -{ - uint16_t reply; - int base; - - assert(l2_img->format == L2I_MFS); - - base = (AB_address >> 1) * 3; - - if (! (AB_address & 1)) - reply = (l2_img->u.mfs.ABlink[base] << 4) | ((l2_img->u.mfs.ABlink[base+1] >> 4) & 0x0f); - else - reply = ((l2_img->u.mfs.ABlink[base+1] << 8) & 0xf00) | l2_img->u.mfs.ABlink[base+2]; - - return reply; -} - -/* - mfs_set_ABlink - - Set one entry of the Allocation Bitmap link array, on an MFS volume. - - l2_img (I/O): level-2 image reference - AB_address (I): index in the array, which is an AB address - data (I): 12-bit value to write in array -*/ -static void mfs_set_ABlink(struct mac_l2_imgref *l2_img, uint16_t AB_address, uint16_t data) -{ - int base; - - assert(l2_img->format == L2I_MFS); - - base = (AB_address >> 1) * 3; - - if (! (AB_address & 1)) - { - l2_img->u.mfs.ABlink[base] = (data >> 4) & 0xff; - l2_img->u.mfs.ABlink[base+1] = (l2_img->u.mfs.ABlink[base+1] & 0x0f) | ((data << 4) & 0xf0); - - l2_img->u.mfs.ABlink_dirty[(base+64)/512] = 1; - l2_img->u.mfs.ABlink_dirty[(base+1+64)/512] = 1; - } - else - { - l2_img->u.mfs.ABlink[base+1] = (l2_img->u.mfs.ABlink[base+1] & 0xf0) | ((data >> 8) & 0x0f); - l2_img->u.mfs.ABlink[base+2] = data & 0xff; - - l2_img->u.mfs.ABlink_dirty[(base+1+64)/512] = 1; - l2_img->u.mfs.ABlink_dirty[(base+2+64)/512] = 1; - } -} - -/* - mfs_file_get_nth_block_address - - Get the disk block address of a given block in an open file on a MFS image. - Called by macintosh file code. - - fileref (I/O): open mac file reference - block_num (I): file block index - block_address (O): disk block address for the file block - - Return imgtool error code -*/ -static imgtoolerr_t mfs_file_get_nth_block_address(struct mac_fileref *fileref, uint32_t block_num, uint32_t *block_address) -{ - uint32_t AB_num; - uint32_t i; - uint16_t AB_address; - - assert(fileref->l2_img->format == L2I_MFS); - - AB_num = block_num / fileref->l2_img->blocksperAB; - - AB_address = fileref->mfs.stBlk; - if ((AB_address == 0) || (AB_address >= fileref->l2_img->numABs+2)) - /* 0 -> ??? */ - return IMGTOOLERR_CORRUPTIMAGE; - if (AB_address == 1) - /* EOF */ - return IMGTOOLERR_UNEXPECTED; - AB_address -= 2; - for (i=0; i<AB_num; i++) - { - AB_address = mfs_get_ABlink(fileref->l2_img, AB_address); - if ((AB_address == 0) || (AB_address >= fileref->l2_img->numABs+2)) - /* 0 -> empty block: there is no way an empty block could make it - into the link chain!!! */ - return IMGTOOLERR_CORRUPTIMAGE; - if (AB_address == 1) - /* EOF */ - return IMGTOOLERR_UNEXPECTED; - AB_address -= 2; - } - - *block_address = fileref->l2_img->u.mfs.ABStart + AB_address * fileref->l2_img->blocksperAB - + block_num % fileref->l2_img->blocksperAB; - - return IMGTOOLERR_SUCCESS; -} - -/* - mfs_file_allocABs - - Allocate a chunk of ABs - - fileref (I/O): open mac file reference - lastAB (I): AB address on disk of last file AB (only if - fileref->mfs.stBlk != 1) - allocABs (I): number of ABs to allocate in addition to the current file - allocation - fblock (I): first file block to allocate (used for tag data) - - Return imgtool error code -*/ -static imgtoolerr_t mfs_file_allocABs(struct mac_fileref *fileref, uint16_t lastAB, uint32_t allocABs, uint32_t fblock) -{ - int numABs = fileref->l2_img->numABs; - int free_ABs; - int i, j; - floppy_tag_record tag; - int extentBaseAB, extentABlen; - int firstBestExtentBaseAB = 0, firstBestExtentABlen; - int secondBestExtentBaseAB = 0, secondBestExtentABlen; - imgtoolerr_t err; - - /* return if done */ - if (! allocABs) - return IMGTOOLERR_SUCCESS; - - /* compute free space */ - free_ABs = 0; - for (i=0; i<numABs; i++) - { - if (mfs_get_ABlink(fileref->l2_img, i) == 0) - { - if (TAG_CHECKS) - { - /* optional check */ - if (image_get_tag_len(&fileref->l2_img->l1_img) == 12) - { - for (j=0; j<fileref->l2_img->blocksperAB; j++) - { - err = image_read_tag(&fileref->l2_img->l1_img, fileref->l2_img->u.mfs.ABStart + i * fileref->l2_img->blocksperAB + j, &tag); - if (err) - return err; - - if (get_UINT32BE(tag.fileID) != 0) - { - /*return IMGTOOLERR_CORRUPTIMAGE;*/ - goto corrupt_free_block; - } - } - } - } - - free_ABs++; - } -corrupt_free_block: - ; - } - - /* check we have enough free space */ - if (free_ABs < allocABs) - return IMGTOOLERR_NOSPACE; - - if (fileref->mfs.stBlk != 1) - { /* try to extend last file extent */ - /* append free ABs after last AB */ - for (i=lastAB+1; (mfs_get_ABlink(fileref->l2_img, i) == 0) && (allocABs > 0) && (i < numABs); i++) - { - if (TAG_CHECKS) - { - /* optional check */ - if (image_get_tag_len(&fileref->l2_img->l1_img) == 12) - { - for (j=0; j<fileref->l2_img->blocksperAB; j++) - { - err = image_read_tag(&fileref->l2_img->l1_img, fileref->l2_img->u.mfs.ABStart + i * fileref->l2_img->blocksperAB + j, &tag); - if (err) - return err; - - if (get_UINT32BE(tag.fileID) != 0) - { - /*return IMGTOOLERR_CORRUPTIMAGE;*/ - goto corrupt_free_block2; - } - } - } - } - - mfs_set_ABlink(fileref->l2_img, lastAB, i+2); - lastAB = i; - allocABs--; - free_ABs--; - } -corrupt_free_block2: - /* return if done */ - if (! allocABs) - { - mfs_set_ABlink(fileref->l2_img, lastAB, 1); - fileref->l2_img->freeABs = free_ABs; - return IMGTOOLERR_SUCCESS; /* done */ - } - } - - while (allocABs) - { - /* find smallest data block at least nb_alloc_physrecs in length, and largest data block less than nb_alloc_physrecs in length */ - firstBestExtentABlen = INT_MAX; - secondBestExtentABlen = 0; - for (i=0; i<numABs; i++) - { - if (mfs_get_ABlink(fileref->l2_img, i) == 0) - { /* found one free block */ - /* compute its length */ - extentBaseAB = i; - extentABlen = 0; - while ((i<numABs) && (mfs_get_ABlink(fileref->l2_img, i) == 0)) - { - if (TAG_CHECKS) - { - /* optional check */ - if (image_get_tag_len(&fileref->l2_img->l1_img) == 12) - { - for (j=0; j<fileref->l2_img->blocksperAB; j++) - { - err = image_read_tag(&fileref->l2_img->l1_img, fileref->l2_img->u.mfs.ABStart + i * fileref->l2_img->blocksperAB + j, &tag); - if (err) - return err; - - if (get_UINT32BE(tag.fileID) != 0) - { - /*return IMGTOOLERR_CORRUPTIMAGE;*/ - goto corrupt_free_block3; - } - } - } - } - - extentABlen++; - i++; - } -corrupt_free_block3: - /* compare to previous best and second-best blocks */ - if ((extentABlen < firstBestExtentABlen) && (extentABlen >= allocABs)) - { - firstBestExtentBaseAB = extentBaseAB; - firstBestExtentABlen = extentABlen; - if (extentABlen == allocABs) - /* no need to search further */ - break; - } - else if ((extentABlen > secondBestExtentABlen) && (extentABlen < allocABs)) - { - secondBestExtentBaseAB = extentBaseAB; - secondBestExtentABlen = extentABlen; - } - } - } - - if (firstBestExtentABlen != INT_MAX) - { /* found one contiguous block which can hold it all */ - extentABlen = allocABs; - for (i=0; i<allocABs; i++) - { - if (fileref->mfs.stBlk != 1) - mfs_set_ABlink(fileref->l2_img, lastAB, firstBestExtentBaseAB+i+2); - else - fileref->mfs.stBlk = firstBestExtentBaseAB+i+2; - lastAB = firstBestExtentBaseAB+i; - free_ABs--; - /* set tag to allocated */ - if (image_get_tag_len(&fileref->l2_img->l1_img) == 12) - { - set_UINT32BE(&tag.fileID, fileref->fileID); - tag.ftype = 1; - if ((fileref->forkType) == rsrc_fork) - tag.ftype |= 2; - tag.fattr = /*fattr*/ 0; /* ***TODO*** */ - for (j=0; j<fileref->l2_img->blocksperAB; j++) - { - set_UINT16BE(&tag.fblock, fblock & 0xffff); - set_UINT32BE(&tag.wrCnt, mac_time_now()); - err = image_write_tag(&fileref->l2_img->l1_img, fileref->l2_img->u.mfs.ABStart + lastAB * fileref->l2_img->blocksperAB + j, &tag); - if (err) - { - mfs_set_ABlink(fileref->l2_img, lastAB, 1); - fileref->l2_img->freeABs = free_ABs; - return err; - } - fblock++; - } - } - } - allocABs = 0; - mfs_set_ABlink(fileref->l2_img, lastAB, 1); - fileref->l2_img->freeABs = free_ABs; - /*return IMGTOOLERR_SUCCESS;*/ /* done */ - } - else if (secondBestExtentABlen != 0) - { /* jeez, we need to fragment it. We use the largest smaller block to limit fragmentation. */ - for (i=0; i<secondBestExtentABlen; i++) - { - if (fileref->mfs.stBlk != 1) - mfs_set_ABlink(fileref->l2_img, lastAB, secondBestExtentBaseAB+i+2); - else - fileref->mfs.stBlk = secondBestExtentBaseAB+i+2; - lastAB = secondBestExtentBaseAB+i; - free_ABs--; - /* set tag to allocated */ - if (image_get_tag_len(&fileref->l2_img->l1_img) == 12) - { - set_UINT32BE(&tag.fileID, fileref->fileID); - tag.ftype = 1; - if ((fileref->forkType) == rsrc_fork) - tag.ftype |= 2; - tag.fattr = /*fattr*/ 0; /* ***TODO*** */ - for (j=0; j<fileref->l2_img->blocksperAB; j++) - { - set_UINT16BE(&tag.fblock, fblock & 0xffff); - set_UINT32BE(&tag.wrCnt, mac_time_now()); - err = image_write_tag(&fileref->l2_img->l1_img, fileref->l2_img->u.mfs.ABStart + lastAB * fileref->l2_img->blocksperAB + j, &tag); - if (err) - { - mfs_set_ABlink(fileref->l2_img, lastAB, 1); - fileref->l2_img->freeABs = free_ABs; - return err; - } - fblock++; - } - } - } - allocABs -= secondBestExtentABlen; - } - else - { - mfs_set_ABlink(fileref->l2_img, lastAB, 1); - return IMGTOOLERR_NOSPACE; /* This should never happen, as we pre-check that there is enough free space */ - } - } - - return IMGTOOLERR_SUCCESS; -} - -/* - mfs_file_setABeof - - Set physical file EOF in ABs - - fileref (I/O): open mac file reference - newABeof (I): desired number of allocated ABs for this file - - Return imgtool error code -*/ -static imgtoolerr_t mfs_file_setABeof(struct mac_fileref *fileref, uint32_t newABeof) -{ - uint16_t AB_address = 0; - uint16_t AB_link; - int i, j; - floppy_tag_record tag; - int MDB_dirty = 0; - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - - - assert(fileref->l2_img->format == L2I_MFS); - - /* run through link chain until we reach the old or the new EOF */ - AB_link = fileref->mfs.stBlk; - if ((AB_link == 0) || (AB_link >= fileref->l2_img->numABs+2)) - /* 0 -> ??? */ - return IMGTOOLERR_CORRUPTIMAGE; - for (i=0; (i<newABeof) && (AB_link!=1); i++) - { - AB_address = AB_link - 2; - AB_link = mfs_get_ABlink(fileref->l2_img, AB_address); - if ((AB_link == 0) || (AB_link >= fileref->l2_img->numABs+2)) - /* 0 -> empty block: there is no way an empty block could make it - into the link chain!!! */ - return IMGTOOLERR_CORRUPTIMAGE; - - if (TAG_CHECKS) - { - /* optional check */ - if (image_get_tag_len(&fileref->l2_img->l1_img) == 12) - { - for (j=0; j<fileref->l2_img->blocksperAB; j++) - { - err = image_read_tag(&fileref->l2_img->l1_img, fileref->l2_img->u.mfs.ABStart + AB_address * fileref->l2_img->blocksperAB + j, &tag); - if (err) - return err; - - if ((get_UINT32BE(tag.fileID) != fileref->fileID) - || (((tag.ftype & 2) != 0) != (fileref->forkType == rsrc_fork)) - || (get_UINT16BE(tag.fblock) != ((i * fileref->l2_img->blocksperAB + j) & 0xffff))) - { - return IMGTOOLERR_CORRUPTIMAGE; - } - } - } - } - } - - if (i == newABeof) - { /* new EOF is shorter than old one */ - /* mark new eof */ - if (i==0) - fileref->mfs.stBlk = 1; - else - { - mfs_set_ABlink(fileref->l2_img, AB_address, 1); - MDB_dirty = 1; - } - - /* free all remaining blocks */ - while (AB_link != 1) - { - AB_address = AB_link - 2; - AB_link = mfs_get_ABlink(fileref->l2_img, AB_address); - if ((AB_link == 0) || (AB_link >= fileref->l2_img->numABs+2)) - { /* 0 -> empty block: there is no way an empty block could make - it into the link chain!!! */ - if (MDB_dirty) - { /* update MDB (freeABs field) and ABLink array */ - err = mfs_update_mdb(fileref->l2_img); - if (err) - return err; - } - return IMGTOOLERR_CORRUPTIMAGE; - } - - if (TAG_CHECKS) - { - /* optional check */ - if (image_get_tag_len(&fileref->l2_img->l1_img) == 12) - { - for (j=0; j<fileref->l2_img->blocksperAB; j++) - { - err = image_read_tag(&fileref->l2_img->l1_img, fileref->l2_img->u.mfs.ABStart + AB_address * fileref->l2_img->blocksperAB + j, &tag); - if (err) - return err; - - if ((get_UINT32BE(tag.fileID) != fileref->fileID) - || (((tag.ftype & 2) != 0) != (fileref->forkType == rsrc_fork)) - || (get_UINT16BE(tag.fblock) != ((i * fileref->l2_img->blocksperAB + j) & 0xffff))) - { - return IMGTOOLERR_CORRUPTIMAGE; - } - } - } - } - - mfs_set_ABlink(fileref->l2_img, AB_address, 0); - fileref->l2_img->freeABs++; - MDB_dirty = 1; - /* set tag to free */ - if (image_get_tag_len(&fileref->l2_img->l1_img) == 12) - { - memset(&tag, 0, sizeof(tag)); - for (j=0; j<fileref->l2_img->blocksperAB; j++) - { - err = image_write_tag(&fileref->l2_img->l1_img, fileref->l2_img->u.mfs.ABStart + AB_address * fileref->l2_img->blocksperAB + j, &tag); - if (err) - return err; - } - } - i++; - } - } - else - { /* new EOF is larger than old one */ - err = mfs_file_allocABs(fileref, AB_address, newABeof - i, i * fileref->l2_img->blocksperAB); - if (err) - return err; - MDB_dirty = 1; - } - - if (MDB_dirty) - { /* update MDB (freeABs field) and ABLink array */ - err = mfs_update_mdb(fileref->l2_img); - if (err) - return err; - } - - fileref->pLen = newABeof * (fileref->l2_img->blocksperAB * 512); - - return IMGTOOLERR_SUCCESS; -} - -#ifdef UNUSED_FUNCTION -/* - mfs_hashString - - Hash a string: under MFS, this provides the resource ID of the comment - resource associated with the file whose name is provided (FCMT resource - type). - - Ripped from Apple technote TB06 (converted from 68k ASM to C) - - string (I): string to hash - - Returns hash value -*/ -static int mfs_hashString(const mac_str255 string) -{ - int reply; - int len; - int i; - - len = string[0]; - - reply = 0; - for (i=0; i<len; i++) - { - reply ^= string[i+1]; - if (reply & 1) - reply = ((reply >> 1) & 0x7fff) | ~0x7fff; - else - reply = ((reply >> 1) & 0x7fff); - if (! (reply & 0x8000)) - reply = - reply; - } - - return reply; -} -#endif - -#if 0 -#pragma mark - -#pragma mark HFS IMPLEMENTATION -#endif - -/* - HFS extents B-tree key -*/ -struct hfs_extentKey -{ - uint8_t keyLength; /* length of key, excluding this field */ - uint8_t forkType; /* 0 = data fork, FF = resource fork */ - UINT32BE fileID; /* file ID */ - UINT16BE startBlock; /* first file allocation block number in this extent */ -}; -enum -{ - keyLength_hfs_extentKey = sizeof(hfs_extentKey) - sizeof(uint8_t) -}; - -/* - HFS catalog B-tree key -*/ -struct hfs_catKey -{ - uint8_t keyLen; /* key length */ - uint8_t resrv1; /* reserved */ - UINT32BE parID; /* parent directory ID */ - mac_str31 cName; /* catalog node name */ - /* note that in index nodes, it is a mac_str31, but - in leaf keys it's a variable-length string */ -}; - -/* - HFS catalog data record for a folder - 70 bytes -*/ -struct hfs_catFolderData -{ - UINT16BE recordType; /* record type */ - UINT16BE flags; /* folder flags */ - UINT16BE valence; /* folder valence */ - UINT32BE folderID; /* folder ID */ - UINT32BE createDate; /* date and time of creation */ - UINT32BE modifyDate; /* date and time of last modification */ - UINT32BE backupDate; /* date and time of last backup */ - mac_DInfo userInfo; /* Finder information */ - mac_DXInfo finderInfo; /* additional Finder information */ - UINT32BE reserved[4]; /* reserved - set to zero */ -}; - -/* - HFS catalog data record for a file - 102 bytes -*/ -struct hfs_catFileData -{ - UINT16BE recordType; /* record type */ - uint8_t flags; /* file flags */ - uint8_t fileType; /* file type (reserved, always 0?) */ - mac_FInfo userInfo; /* Finder information */ - UINT32BE fileID; /* file ID */ - UINT16BE dataStartBlock; /* not used - set to zero */ - UINT32BE dataLogicalSize; /* logical EOF of data fork */ - UINT32BE dataPhysicalSize; /* physical EOF of data fork */ - UINT16BE rsrcStartBlock; /* not used - set to zero */ - UINT32BE rsrcLogicalSize; /* logical EOF of resource fork */ - UINT32BE rsrcPhysicalSize; /* physical EOF of resource fork */ - UINT32BE createDate; /* date and time of creation */ - UINT32BE modifyDate; /* date and time of last modification */ - UINT32BE backupDate; /* date and time of last backup */ - mac_FXInfo finderInfo; /* additional Finder information */ - UINT16BE clumpSize; /* file clump size (not used) */ - hfs_extent_3 dataExtents; /* first data fork extent record */ - hfs_extent_3 rsrcExtents; /* first resource fork extent record */ - UINT32BE reserved; /* reserved - set to zero */ -}; - -/* - HFS catalog data record for a thread - 46 bytes - - The key for a thread record features the CNID of the item and an empty - name, instead of the CNID of the parent and the item name. -*/ -struct hfs_catThreadData -{ - UINT16BE recordType; /* record type */ - UINT32BE reserved[2]; /* reserved - set to zero */ - UINT32BE parID; /* parent ID for this catalog node */ - mac_str31 nodeName; /* name of this catalog node */ -}; - -/* - union for all types at once -*/ -union hfs_catData -{ - UINT16BE dataType; - hfs_catFolderData folder; - hfs_catFileData file; - hfs_catThreadData thread; -}; - -/* - HFS catalog record types -*/ -enum -{ - hcrt_Folder = 0x0100, /* Folder record */ - hcrt_File = 0x0200, /* File record */ - hcrt_FolderThread = 0x0300, /* Folder thread record */ - hcrt_FileThread = 0x0400 /* File thread record */ -}; - -/* - Catalog file record flags - - This is similar to the MFS catalog flag field, but the "thread exists" flag - (0x02) is specific to HFS/HFS+, whereas the "Record in use" flag (0x80) is - only used by MFS. -*/ -enum -{ - cfrf_fileLocked = 0x01, /* file is locked and cannot be written to */ - cfrf_threadExists = 0x02 /* a file thread record exists for this file */ -}; - -/* - BT functions used by HFS functions -*/ -struct BT_leaf_rec_enumerator -{ - mac_BTref *BTref; - uint32_t cur_node; - int cur_rec; -}; - -static imgtoolerr_t BT_open(mac_BTref *BTref, int (*key_compare_func)(const void *key1, const void *key2), int is_extent); -static void BT_close(mac_BTref *BTref); -static imgtoolerr_t BT_search_leaf_rec(mac_BTref *BTref, const void *search_key, - uint32_t *node_ID, int *record_ID, - void **record_ptr, int *record_len, - int search_exact_match, int *match_found); -static imgtoolerr_t BT_get_keyed_record_data(mac_BTref *BTref, void *rec_ptr, int rec_len, void **data_ptr, int *data_len); -static imgtoolerr_t BT_leaf_rec_enumerator_open(mac_BTref *BTref, BT_leaf_rec_enumerator *enumerator); -static imgtoolerr_t BT_leaf_rec_enumerator_read(BT_leaf_rec_enumerator *enumerator, void **record_ptr, int *rec_len); - -struct hfs_cat_enumerator -{ - struct mac_l2_imgref *l2_img; - BT_leaf_rec_enumerator BT_enumerator; - uint32_t parID; -}; - -/* - hfs_open_extents_file - - Open the file extents B-tree file - - l2_img (I/O): level-2 image reference - mdb (I): copy of the MDB block - fileref (O): mac open file reference - - Return imgtool error code -*/ -static imgtoolerr_t hfs_open_extents_file(struct mac_l2_imgref *l2_img, const struct hfs_mdb *mdb, struct mac_fileref *fileref) -{ - assert(l2_img->format == L2I_HFS); - - fileref->l2_img = l2_img; - - fileref->fileID = 3; - fileref->forkType = (mac_forkID)0x00; - - fileref->eof = fileref->pLen = get_UINT32BE(mdb->xtFlSize); - memcpy(fileref->hfs.extents, mdb->xtExtRec, sizeof(hfs_extent_3)); - - fileref->crPs = 0; - - fileref->reload_buf = true; - - return IMGTOOLERR_SUCCESS; -} - -/* - hfs_open_cat_file - - Open the disk catalog B-tree file - - l2_img (I/O): level-2 image reference - mdb (I): copy of the MDB block - fileref (O): mac open file reference - - Return imgtool error code -*/ -static imgtoolerr_t hfs_open_cat_file(struct mac_l2_imgref *l2_img, const struct hfs_mdb *mdb, struct mac_fileref *fileref) -{ - assert(l2_img->format == L2I_HFS); - - fileref->l2_img = l2_img; - - fileref->fileID = 4; - fileref->forkType = (mac_forkID)0x00; - - fileref->eof = fileref->pLen = get_UINT32BE(mdb->ctFlSize); - memcpy(fileref->hfs.extents, mdb->ctExtRec, sizeof(hfs_extent_3)); - - fileref->crPs = 0; - - fileref->reload_buf = true; - - return IMGTOOLERR_SUCCESS; -} - -/* - hfs_extentKey_compare - - key compare function for file extents B-tree - - p1 (I): pointer to first key - p2 (I): pointer to second key - - Return a zero the two keys are equal, a negative value if the key pointed - to by p1 is less than the key pointed to by p2, and a positive value if the - key pointed to by p1 is greater than the key pointed to by p2. -*/ -static int hfs_extentKey_compare(const void *p1, const void *p2) -{ - const hfs_extentKey *key1 = (const hfs_extentKey*)p1; - const hfs_extentKey *key2 = (const hfs_extentKey*)p2; - - /* let's keep it simple for now */ - return memcmp(key1, key2, sizeof(hfs_extentKey)); -} - -/* - hfs_catKey_compare - - key compare function for disk catalog B-tree - - p1 (I): pointer to first key - p2 (I): pointer to second key - - Return a zero the two keys are equal, a negative value if the key pointed - to by p1 is less than the key pointed to by p2, and a positive value if the - key pointed to by p1 is greater than the key pointed to by p2. -*/ -static int hfs_catKey_compare(const void *p1, const void *p2) -{ - const hfs_catKey *key1 = (const hfs_catKey *)p1; - const hfs_catKey *key2 = (const hfs_catKey *)p2; - - if (get_UINT32BE(key1->parID) != get_UINT32BE(key2->parID)) - return (get_UINT32BE(key1->parID) < get_UINT32BE(key2->parID)) ? -1 : +1; - - return mac_stricmp(key1->cName, key2->cName); -} - -/* - hfs_image_open - - Open a HFS image. Image must already be open on level 1. - - l2_img (I/O): level-2 image reference to open (l1_img and format fields - must be initialized) - img_open_buf (I): buffer with the MDB block - - Return imgtool error code -*/ -static imgtoolerr_t hfs_image_open(imgtool::image &image, imgtool::stream::ptr &&stream) -{ - imgtoolerr_t err; - struct mac_l2_imgref *l2_img; - img_open_buf buf_local; - img_open_buf *buf; - - l2_img = get_imgref(image); - l2_img->l1_img.image = ℑ - l2_img->l1_img.heads = 2; - l2_img->format = L2I_HFS; - - /* read MDB */ - err = image_read_block(&l2_img->l1_img, 2, &buf_local.raw); - if (err) - return err; - buf = &buf_local; - - /* check signature word */ - if ((buf->hfs_mdb.sigWord[0] != 0x42) || (buf->hfs_mdb.sigWord[1] != 0x44) - || (buf->hfs_mdb.VN[0] > 27)) - return IMGTOOLERR_CORRUPTIMAGE; - - l2_img->u.hfs.VBM_start = get_UINT16BE(buf->hfs_mdb.VBMSt); - - l2_img->numABs = get_UINT16BE(buf->hfs_mdb.nmAlBlks); - if (get_UINT32BE(buf->hfs_mdb.alBlkSiz) % 512) - return IMGTOOLERR_CORRUPTIMAGE; - l2_img->blocksperAB = get_UINT32BE(buf->hfs_mdb.alBlkSiz) / 512; - l2_img->u.hfs.ABStart = get_UINT16BE(buf->hfs_mdb.alBlSt); - - l2_img->nxtCNID = get_UINT32BE(buf->hfs_mdb.nxtCNID); - - l2_img->freeABs = get_UINT16BE(buf->hfs_mdb.freeABs); - - mac_strcpy(l2_img->u.hfs.volname, buf->hfs_mdb.VN); - - /* open extents and catalog BT */ - err = hfs_open_extents_file(l2_img, &buf->hfs_mdb, &l2_img->u.hfs.extents_BT.fileref); - if (err) - return err; - err = BT_open(&l2_img->u.hfs.extents_BT, hfs_extentKey_compare, true); - if (err) - return err; - if ((l2_img->u.hfs.extents_BT.attributes & btha_bigKeysMask) - /*|| (l2_img->u.hfs.extents_BT.attributes & kBTVariableIndexKeysMask)*/ - || (l2_img->u.hfs.extents_BT.maxKeyLength != 7)) - { /* This is not supported by the HFS format */ - /* Variable Index keys are not supported either, but hopefully it will - not break this imgtool module if it set (though it would probably break - a real macintosh) */ - BT_close(&l2_img->u.hfs.extents_BT); - return IMGTOOLERR_CORRUPTIMAGE; - } - err = hfs_open_cat_file(l2_img, &buf->hfs_mdb, &l2_img->u.hfs.cat_BT.fileref); - if (err) - { - BT_close(&l2_img->u.hfs.extents_BT); - return err; - } - err = BT_open(&l2_img->u.hfs.cat_BT, hfs_catKey_compare, false); - if (err) - { - return err; - } - if ((l2_img->u.hfs.cat_BT.attributes & btha_bigKeysMask) - /*|| (l2_img->u.hfs.cat_BT.attributes & kBTVariableIndexKeysMask)*/ - || (l2_img->u.hfs.cat_BT.maxKeyLength != 37)) - { /* This is not supported by the HFS format */ - /* Variable Index keys are not supported either, but hopefully it will - not break this imgtool module if it set (though it would probably break - a real macintosh) */ - BT_close(&l2_img->u.hfs.extents_BT); - BT_close(&l2_img->u.hfs.cat_BT); - return IMGTOOLERR_CORRUPTIMAGE; - } - - /* extract volume bitmap */ - { - int byte_len = (l2_img->numABs + 7) / 8; - int cur_byte = 0; - int cur_block = l2_img->u.hfs.VBM_start; - - while (cur_byte < byte_len) - { - /* read next block */ - err = image_read_block(&l2_img->l1_img, cur_block, buf->raw); - if (err) - return err; - cur_block++; - - /* append this block to VBM */ - memcpy(l2_img->u.hfs.VBM+cur_byte, buf->raw, 512); - cur_byte += 512; - } - } - - return IMGTOOLERR_SUCCESS; -} - -#ifdef UNUSED_FUNCTION -/* - hfs_image_close - - Close a HFS image. - - l2_img (I/O): level-2 image reference -*/ -static void hfs_image_close(struct mac_l2_imgref *l2_img) -{ - assert(l2_img->format == L2I_HFS); - - BT_close(&l2_img->u.hfs.extents_BT); - BT_close(&l2_img->u.hfs.cat_BT); -} -#endif - -/* - hfs_get_cat_record_data - - extract data from a catalog B-tree leaf record - - l2_img (I/O): level-2 image reference - rec_raw (I): pointer to record key and data, as returned by - BT_node_get_keyed_record - rec_len (I): total length of record, as returned by - BT_node_get_keyed_record - rec_key (O): set to point to record key - rec_data (O): set to point to record data - - Return imgtool error code -*/ -static imgtoolerr_t hfs_get_cat_record_data(struct mac_l2_imgref *l2_img, void *rec_raw, int rec_len, hfs_catKey **rec_key, hfs_catData **rec_data) -{ - hfs_catKey *lrec_key; - void *rec_data_raw; - hfs_catData *lrec_data; - int rec_data_len; - int min_data_size; - imgtoolerr_t err; - - - assert(l2_img->format == L2I_HFS); - - lrec_key = (hfs_catKey*)rec_raw; - /* check that key is long enough to hold it all */ - if ((lrec_key->keyLen+1) < (offsetof(hfs_catKey, cName) + lrec_key->cName[0] + 1)) - return IMGTOOLERR_CORRUPTIMAGE; - - /* get pointer to record data */ - err = BT_get_keyed_record_data(&l2_img->u.hfs.cat_BT, rec_raw, rec_len, &rec_data_raw, &rec_data_len); - if (err) - return err; - lrec_data = (hfs_catData*)rec_data_raw; - - /* extract record type */ - if (rec_data_len < 2) - return IMGTOOLERR_CORRUPTIMAGE; - - /* check that the record is large enough for its type */ - switch (get_UINT16BE(lrec_data->dataType)) - { - case hcrt_Folder: - min_data_size = sizeof(hfs_catFolderData); - break; - - case hcrt_File: - min_data_size = sizeof(hfs_catFileData); - break; - - case hcrt_FolderThread: - case hcrt_FileThread: - min_data_size = sizeof(hfs_catThreadData); - break; - - default: - /* records of unknown type can be safely ignored */ - min_data_size = 0; - break; - } - - if (rec_data_len < min_data_size) - return IMGTOOLERR_CORRUPTIMAGE; - - if (rec_key) - *rec_key = lrec_key; - if (rec_data) - *rec_data = lrec_data; - - return IMGTOOLERR_SUCCESS; -} - -/* - hfs_cat_open - - Open an enumerator on the disk catalog - - l2_img (I/O): level-2 image reference - enumerator (O): open catalog enumerator reference - - Return imgtool error code -*/ -static imgtoolerr_t hfs_cat_open(struct mac_l2_imgref *l2_img, const char *path, hfs_cat_enumerator *enumerator) -{ - imgtoolerr_t err; - uint32_t parID; - mac_str255 filename; - mac_dirent cat_info; - - assert(l2_img->format == L2I_HFS); - - /* resolve path and fetch file info from directory/catalog */ - err = mac_lookup_path(l2_img, path, &parID, filename, &cat_info, false); - if (err) - return err; - if (cat_info.dataRecType != hcrt_Folder) - return IMGTOOLERR_FILENOTFOUND; - - enumerator->l2_img = l2_img; - enumerator->parID = parID; - - return BT_leaf_rec_enumerator_open(&l2_img->u.hfs.cat_BT, &enumerator->BT_enumerator); -} - -/* - hfs_cat_read - - Enumerate the disk catalog - - enumerator (I/O): open catalog enumerator reference - rec_key (O): set to point to record key - rec_data (O): set to point to record data - - Return imgtool error code -*/ -static imgtoolerr_t hfs_cat_read(hfs_cat_enumerator *enumerator, hfs_catKey **rec_key, hfs_catData **rec_data) -{ - void *rec; - int rec_len = 0; - imgtoolerr_t err; - - - *rec_key = NULL; - *rec_data = NULL; - - /* read next record */ - err = BT_leaf_rec_enumerator_read(&enumerator->BT_enumerator, &rec, &rec_len); - if (err) - return err; - - /* check EOList condition */ - if (rec == NULL) - return IMGTOOLERR_SUCCESS; - - /* extract record data */ - err = hfs_get_cat_record_data(enumerator->l2_img, rec, rec_len, rec_key, rec_data); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - -/* - hfs_cat_search - - Search the catalog for a given file - - l2_img (I/O): level-2 image reference - parID (I): CNID of file parent directory - cName (I): file name - rec_key (O): set to point to record key - rec_data (O): set to point to record data - - Return imgtool error code -*/ -static imgtoolerr_t hfs_cat_search(struct mac_l2_imgref *l2_img, uint32_t parID, const mac_str31 cName, hfs_catKey **rec_key, hfs_catData **rec_data) -{ - hfs_catKey search_key; - void *rec; - int rec_len; - imgtoolerr_t err; - - assert(l2_img->format == L2I_HFS); - - if (cName[0] > 31) - return IMGTOOLERR_UNEXPECTED; - - /* generate search key */ - search_key.keyLen = search_key.resrv1 = 0; /* these fields do not matter - to the compare function, so we - don't fill them */ - set_UINT32BE(&search_key.parID, parID); - mac_strcpy(search_key.cName, cName); - - /* search key */ - err = BT_search_leaf_rec(&l2_img->u.hfs.cat_BT, &search_key, NULL, NULL, &rec, &rec_len, true, NULL); - if (err) - return err; - - /* extract record data */ - err = hfs_get_cat_record_data(l2_img, rec, rec_len, rec_key, rec_data); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - -/* - hfs_lookup_path - - Resolve a file path - - l2_img (I/O): level-2 image reference - fpath (I): file path (C string) - parID (O): set to the CNID of the file parent directory - filename (O): set to the actual name of the file, with capitalization matching - the one on the volume rather than the one in the fpath parameter (Mac - string) - cat_info (O): catalog info for this file extracted from the catalog file - (may be NULL) - - Return imgtool error code -*/ -static imgtoolerr_t hfs_lookup_path(struct mac_l2_imgref *l2_img, const char *fpath, uint32_t *parID, mac_str255 filename, mac_dirent *cat_info) -{ - const char *element_start; - int element_len; - mac_str255 mac_element_name; - //int level; - imgtoolerr_t err; - hfs_catKey *catrec_key = NULL; - hfs_catData *catrec_data = NULL; - uint16_t dataRecType = hcrt_Folder; - - /* iterate each path element */ - element_start = fpath; - //level = 0; - *parID = 2; /* root parID is 2 */ - - while(*element_start) - { - /* find next path element */ - element_len = strlen(element_start); - /* decode path element name */ - c_to_mac_strncpy(mac_element_name, element_start, element_len); - - err = hfs_cat_search(l2_img, *parID, mac_element_name, &catrec_key, &catrec_data); - if (err) - return err; - - dataRecType = get_UINT16BE(catrec_data->dataType); - - /* regular folder/file name */ - if (dataRecType == hcrt_Folder) - *parID = get_UINT32BE(catrec_data->folder.folderID); - else if (element_start[element_len + 1]) - return IMGTOOLERR_BADFILENAME; - - /* iterate */ - element_start += element_len + 1; - } - - if (catrec_key && (dataRecType == hcrt_File)) - { - /* save ref */ - *parID = get_UINT32BE(catrec_key->parID); - mac_strcpy(filename, catrec_key->cName); - } - - if (cat_info) - { - if (catrec_data && (dataRecType == hcrt_File)) - { - cat_info->flFinderInfo = catrec_data->file.userInfo; - cat_info->flXFinderInfo = catrec_data->file.finderInfo; - cat_info->flags = catrec_data->file.flags; - cat_info->fileID = get_UINT32BE(catrec_data->file.fileID); - cat_info->dataLogicalSize = get_UINT32BE(catrec_data->file.dataLogicalSize); - cat_info->dataPhysicalSize = get_UINT32BE(catrec_data->file.dataPhysicalSize); - cat_info->rsrcLogicalSize = get_UINT32BE(catrec_data->file.rsrcLogicalSize); - cat_info->rsrcPhysicalSize = get_UINT32BE(catrec_data->file.rsrcPhysicalSize); - cat_info->createDate = get_UINT32BE(catrec_data->file.createDate); - cat_info->modifyDate = get_UINT32BE(catrec_data->file.modifyDate); - } - else - { - memset(cat_info, 0, sizeof(*cat_info)); - } - cat_info->dataRecType = dataRecType; - } - - return IMGTOOLERR_SUCCESS; -} - -/* - hfs_file_open_internal - - Open a file fork, given its catalog entry. This function should not be - called directly: call hfs_file_open instead. - - l2_img (I/O): level-2 image reference - file_rec (I): catalog entry for the file to open - mac_forkID (I): tells which fork should be opened - fileref (O): mac file reference to open - - Return imgtool error code -*/ -static imgtoolerr_t hfs_file_open_internal(struct mac_l2_imgref *l2_img, const hfs_catFileData *file_rec, mac_forkID fork, struct mac_fileref *fileref) -{ - assert(l2_img->format == L2I_HFS); - - fileref->l2_img = l2_img; - - fileref->fileID = get_UINT32BE(file_rec->fileID); - fileref->forkType = fork; - - switch (fork) - { - case data_fork: - fileref->eof = get_UINT32BE(file_rec->dataLogicalSize); - fileref->pLen = get_UINT32BE(file_rec->dataPhysicalSize); - memcpy(fileref->hfs.extents, file_rec->dataExtents, sizeof(hfs_extent_3)); - break; - - case rsrc_fork: - fileref->eof = get_UINT32BE(file_rec->rsrcLogicalSize); - fileref->pLen = get_UINT32BE(file_rec->rsrcPhysicalSize); - memcpy(fileref->hfs.extents, file_rec->rsrcExtents, sizeof(hfs_extent_3)); - break; - } - - fileref->crPs = 0; - - fileref->reload_buf = true; - - return IMGTOOLERR_SUCCESS; -} - -/* - hfs_file_open - - Open a file located on a HFS volume. This function should not be called - directly: call mac_file_open instead. - - l2_img (I/O): level-2 image reference - parID (I): CNID of file parent directory - filename (I): name of the file (Mac string) - mac_forkID (I): tells which fork should be opened - fileref (O): mac file reference to open - - Return imgtool error code -*/ -static imgtoolerr_t hfs_file_open(struct mac_l2_imgref *l2_img, uint32_t parID, const mac_str255 filename, mac_forkID fork, struct mac_fileref *fileref) -{ - hfs_catKey *catrec_key; - hfs_catData *catrec_data; - uint16_t dataRecType; - imgtoolerr_t err; - - /* lookup file in catalog */ - err = hfs_cat_search(l2_img, parID, filename, &catrec_key, &catrec_data); - if (err) - return err; - - dataRecType = get_UINT16BE(catrec_data->dataType); - - /* file expected */ - if (dataRecType != hcrt_File) - return IMGTOOLERR_BADFILENAME; - - fileref->hfs.parID = get_UINT32BE(catrec_key->parID); - mac_strcpy(fileref->hfs.filename, catrec_key->cName); - - /* open it */ - return hfs_file_open_internal(l2_img, &catrec_data->file, fork, fileref); -} - -/* - hfs_file_get_nth_block_address - - Get the disk block address of a given block in an open file on a MFS image. - Called by macintosh file code. - - fileref (I/O): open mac file reference - block_num (I): file block index - block_address (O): disk block address for the file block - - Return imgtool error code -*/ -static imgtoolerr_t hfs_file_get_nth_block_address(struct mac_fileref *fileref, uint32_t block_num, uint32_t *block_address) -{ - uint32_t AB_num; - uint32_t cur_AB; - uint32_t i; - void *cur_extents_raw; - hfs_extent *cur_extents; - int cur_extents_len; - void *extents_BT_rec; - int extents_BT_rec_len; - imgtoolerr_t err; - uint16_t AB_address; - - assert(fileref->l2_img->format == L2I_HFS); - - AB_num = block_num / fileref->l2_img->blocksperAB; - cur_AB = 0; - cur_extents = fileref->hfs.extents; - - /* first look in catalog tree extents */ - for (i=0; i<3; i++) - { - if (AB_num < cur_AB+get_UINT16BE(cur_extents[i].numABlks)) - break; - cur_AB += get_UINT16BE(cur_extents[i].numABlks); - } - if (i == 3) - { - /* extent not found: read extents record from extents BT */ - hfs_extentKey search_key; - hfs_extentKey *found_key; - - search_key.keyLength = keyLength_hfs_extentKey; - search_key.forkType = fileref->forkType; - set_UINT32BE(&search_key.fileID, fileref->fileID); - set_UINT16BE(&search_key.startBlock, AB_num); - - /* search for the record with the largest key lower than or equal to - search_key. The keys are constructed in such a way that, if a record - includes AB_num, it is that one. */ - err = BT_search_leaf_rec(&fileref->l2_img->u.hfs.extents_BT, &search_key, - NULL, NULL, &extents_BT_rec, &extents_BT_rec_len, - false, NULL); - if (err) - return err; - - if (extents_BT_rec == NULL) - return IMGTOOLERR_CORRUPTIMAGE; - - found_key = (hfs_extentKey*)extents_BT_rec; - /* check that this record concerns the correct file */ - if ((found_key->forkType != fileref->forkType) - || (get_UINT32BE(found_key->fileID) != fileref->fileID)) - return IMGTOOLERR_CORRUPTIMAGE; - - /* extract start AB */ - cur_AB = get_UINT16BE(found_key->startBlock); - /* get extents pointer */ - err = BT_get_keyed_record_data(&fileref->l2_img->u.hfs.extents_BT, extents_BT_rec, extents_BT_rec_len, &cur_extents_raw, &cur_extents_len); - if (err) - return err; - if (cur_extents_len < 3*sizeof(hfs_extent)) - return IMGTOOLERR_CORRUPTIMAGE; - cur_extents = (hfs_extent*)cur_extents_raw; - - /* pick correct extent in record */ - for (i=0; i<3; i++) - { - if (AB_num < cur_AB+get_UINT16BE(cur_extents[i].numABlks)) - break; - cur_AB += get_UINT16BE(cur_extents[i].numABlks); - } - if (i == 3) - /* extent not found */ - return IMGTOOLERR_CORRUPTIMAGE; - } - - AB_address = get_UINT16BE(cur_extents[i].stABN) + (AB_num-cur_AB); - - if (AB_address >= fileref->l2_img->numABs) - return IMGTOOLERR_CORRUPTIMAGE; - - *block_address = fileref->l2_img->u.hfs.ABStart + AB_address * fileref->l2_img->blocksperAB - + block_num % fileref->l2_img->blocksperAB; - - return IMGTOOLERR_SUCCESS; -} - -#if 0 -#pragma mark - -#pragma mark B-TREE IMPLEMENTATION -#endif - -/* - B-tree (Balanced search tree) files are used by the HFS and HFS+ file - systems: the Extents and Catalog files are both B-Tree. - - Note that these B-trees are B+-trees: data is only on the leaf level, and - nodes located on the same level are also linked sequentially, which allows - fast sequenctial access to the catalog file. - - These files are normal files, except for the fact that they are not - referenced from the catalog but the MDB. They are allocated in fixed-size - records of 512 bytes (HFS). (HFS+ supports any power of two from 512 - through 32768, and uses a default of 1024 for Extents, and 4096 for both - Catalog and Attributes.) - - Nodes can contain any number of records. The nodes can be of any of four - types: header node (unique node with b-tree information, pointer to root - node and start of the node allocation bitmap), map nodes (which are created - when the node allocation bitmap outgrows the header node), index nodes - (root and branch node that enable to efficiently search the leaf nodes for - a specific key value), and leaf nodes (which hold the actual user data - records with keys and data). The first node is always a header node. - Other nodes can be of any of the 3 other type, or they can be free. -*/ - -/* - BTNodeHeader - - Header of a node record -*/ -struct BTNodeHeader -{ - UINT32BE fLink; /* (index of) next node at this level */ - UINT32BE bLink; /* (index of) previous node at this level */ - uint8_t kind; /* kind of node (leaf, index, header, map) */ - uint8_t height; /* zero for header, map; 1 for leaf, 2 through - treeDepth for index (child is one LESS than - parent, whatever IM says) */ - UINT16BE numRecords; /* number of records in this node */ - UINT16BE reserved; /* reserved; set to zero */ -}; - -/* - Constants for BTNodeHeader kind field -*/ -enum -{ - btnk_leafNode = 0xff, /* leaf nodes hold the actual user data records - with keys and data */ - btnk_indexNode = 0, /* root and branch node that enable to efficiently - search the leaf nodes for a specific key value */ - btnk_headerNode = 1, /* unique node with b-tree information, pointer to - root node and start of the node allocation - bitmap */ - btnk_mapNode = 2 /* map nodes are created when the node allocation - bitmap outgrows the header node */ -}; - -/* - BTHeaderRecord: first record of a B-tree header node (second record is - unused, and third is node allocation bitmap). -*/ -struct BTHeaderRecord -{ - UINT16BE treeDepth; /* maximum height (usually leaf nodes) */ - UINT32BE rootNode; /* node number of root node */ - UINT32BE leafRecords; /* number of leaf records in all leaf nodes */ - UINT32BE firstLeafNode; /* node number of first leaf node */ - UINT32BE lastLeafNode; /* node number of last leaf node */ - UINT16BE nodeSize; /* size of a node, in bytes */ - UINT16BE maxKeyLength; /* maximum length of data (index + leaf) record keys; - length of all index record keys if - btha_variableIndexKeysMask attribute flag is not set */ - UINT32BE totalNodes; /* total number of nodes in tree */ - UINT32BE freeNodes; /* number of unused (free) nodes in tree */ - - UINT16BE reserved1; /* unused */ - UINT32BE clumpSize; /* used in some HFS implementations? (reserved in - early HFS implementations, and in HFS Plus) */ - uint8_t btreeType; /* reserved - set to 0 */ - uint8_t reserved2; /* reserved */ - UINT32BE attributes; /* persistent attributes about the tree */ - UINT32BE reserved3[16]; /* reserved */ -}; - -static imgtoolerr_t BT_check(mac_BTref *BTref, int is_extent); - -/* - BT_open - - Open a file as a B-tree. The file must be already open as a macintosh - file. - - BTref (I/O): B-tree file handle to open (BTref->fileref must have been - open previously) - key_compare_func (I): function that compares two keys - is_extent (I): true if we are opening the extent B-tree (we want to do - extra checks in this case because the extent B-Tree may include extent - records for the extent B-tree itself, and if an extent record for the - extent B-tree is located in an extent that has not been defined by - previous extent records, then we can never retreive this extent record) - - Return imgtool error code -*/ -static imgtoolerr_t BT_open(mac_BTref *BTref, int (*key_compare_func)(const void *key1, const void *key2), int is_extent) -{ - imgtoolerr_t err; - BTNodeHeader node_header; - BTHeaderRecord header_rec; - - /* seek to node 0 */ - err = mac_file_seek(&BTref->fileref, 0); - if (err) - return err; - - /* read node header */ - err = mac_file_read(&BTref->fileref, sizeof(node_header), &node_header); - if (err) - return err; - - if ((node_header.kind != btnk_headerNode) || (get_UINT16BE(node_header.numRecords) < 3) - || (node_header.height != 0)) - return IMGTOOLERR_CORRUPTIMAGE; /* right??? */ - - /* CHEESY HACK: we assume that the header record immediately follows the - node header. This is because we need to know the node length to know where - the record pointers are located, but we need to read the header record to - know the node length. */ - err = mac_file_read(&BTref->fileref, sizeof(header_rec), &header_rec); - if (err) - return err; - - BTref->nodeSize = get_UINT16BE(header_rec.nodeSize); - BTref->rootNode = get_UINT32BE(header_rec.rootNode); - BTref->firstLeafNode = get_UINT32BE(header_rec.firstLeafNode); - BTref->attributes = get_UINT32BE(header_rec.attributes); - BTref->treeDepth = get_UINT16BE(header_rec.treeDepth); - BTref->maxKeyLength = get_UINT16BE(header_rec.maxKeyLength); - - BTref->key_compare_func = key_compare_func; - - BTref->node_buf = malloc(BTref->nodeSize); - if (!BTref->node_buf) - return IMGTOOLERR_OUTOFMEMORY; - - if (BTREE_CHECKS) - { - /* optional: check integrity of B-tree */ - err = BT_check(BTref, is_extent); - if (err) - return err; - } - - return IMGTOOLERR_SUCCESS; -} - -/* - BT_close - - Close a B-tree - - BTref (I/O): open B-tree file handle -*/ -static void BT_close(mac_BTref *BTref) -{ - free(BTref->node_buf); -} - -/* - BT_read_node - - Read a node from a B-tree - - BTref (I/O): open B-tree file handle - node_ID (I): index of the node to read - expected_kind (I): kind of the node to read - expected_depth (I): depth of the node to read - dest (O): destination buffer - - Return imgtool error code -*/ -static imgtoolerr_t BT_read_node(mac_BTref *BTref, uint32_t node_ID, int expected_kind, int expected_depth, void *dest) -{ - imgtoolerr_t err; - - /* seek to node */ - err = mac_file_seek(&BTref->fileref, node_ID*BTref->nodeSize); - if (err) - return err; - - /* read it */ - err = mac_file_read(&BTref->fileref, BTref->nodeSize, dest); - if (err) - return err; - - /* check node kind and depth */ - if ((((BTNodeHeader *) dest)->kind != expected_kind) - || (((BTNodeHeader *) dest)->height != expected_depth)) - return IMGTOOLERR_CORRUPTIMAGE; - - return IMGTOOLERR_SUCCESS; -} - -/* - BT_node_get_record - - Extract a raw record from a B-tree node - - BTref (I/O): open B-tree file handle - node_buf (I): buffer with the node the record should be extracted from - recnum (I): index of record to read - rec_ptr (O): set to point to start of record (key + data) - rec_len (O): set to total length of record (key + data) - - Return imgtool error code -*/ -static imgtoolerr_t BT_node_get_record(mac_BTref *BTref, void *node_buf, unsigned recnum, void **rec_ptr, int *rec_len) -{ - uint16_t node_numRecords = get_UINT16BE(((BTNodeHeader *) node_buf)->numRecords); - uint16_t offset; - uint16_t next_offset; - - if (recnum >= node_numRecords) - return IMGTOOLERR_UNEXPECTED; - - int recnum_s = (int)recnum; - offset = get_UINT16BE(((UINT16BE *)((uint8_t *) node_buf + BTref->nodeSize))[-recnum_s - 1]); - next_offset = get_UINT16BE(((UINT16BE *)((uint8_t *) node_buf + BTref->nodeSize))[-recnum_s - 2]); - - if ((offset < sizeof(BTNodeHeader)) || (offset > BTref->nodeSize-2*node_numRecords) - || (next_offset < sizeof(BTNodeHeader)) || (next_offset > BTref->nodeSize-2*node_numRecords) - || (offset & 1) || (next_offset & 1) - || (offset > next_offset)) - return IMGTOOLERR_CORRUPTIMAGE; - - *rec_ptr = (uint8_t *)node_buf + offset; - *rec_len = next_offset - offset; - - return IMGTOOLERR_SUCCESS; -} - -/* - BT_node_get_keyed_record - - Extract a keyed record from a B-tree node. Equivalent to - BT_node_get_record, only we do extra checks. - - BTref (I/O): open B-tree file handle - node_buf (I): buffer with the node the record should be extracted from - node_is_index (I): true if node is index node - recnum (I): index of record to read - rec_ptr (O): set to point to start of record (key + data) - rec_len (O): set to total length of record (key + data) - - Return imgtool error code -*/ -static imgtoolerr_t BT_node_get_keyed_record(mac_BTref *BTref, void *node_buf, int node_is_index, unsigned recnum, void **rec_ptr, int *rec_len) -{ - imgtoolerr_t err; - void *lrec_ptr; - int lrec_len; - int key_len; - - /* extract record */ - err = BT_node_get_record(BTref, node_buf, recnum, &lrec_ptr, &lrec_len); - if (err) - return err; - - /* read key len */ - key_len = (BTref->attributes & btha_bigKeysMask) - ? get_UINT16BE(* (UINT16BE *)lrec_ptr) - : (* (uint8_t *)lrec_ptr); - - /* check that key fits in record */ - if ((key_len + ((BTref->attributes & btha_bigKeysMask) ? 2 : 1)) > lrec_len) - /* hurk! */ - return IMGTOOLERR_CORRUPTIMAGE; - - if (key_len > BTref->maxKeyLength) - return IMGTOOLERR_CORRUPTIMAGE; - - if (node_is_index && (! (BTref->attributes & btha_variableIndexKeysMask)) && (key_len != BTref->maxKeyLength)) - return IMGTOOLERR_CORRUPTIMAGE; - - if (rec_ptr) - *rec_ptr = lrec_ptr; - if (rec_len) - *rec_len = lrec_len; - - return IMGTOOLERR_SUCCESS; -} - -/* - BT_get_keyed_record_data - - extract data from a keyed record - - BTref (I/O): open B-tree file handle - rec_ptr (I): point to start of record (key + data) - rec_len (I): total length of record (key + data) - data_ptr (O): set to point to record data - data_len (O): set to length of record data - - Return imgtool error code -*/ -static imgtoolerr_t BT_get_keyed_record_data(mac_BTref *BTref, void *rec_ptr, int rec_len, void **data_ptr, int *data_len) -{ - int lkey_len; - int data_offset; - - /* read key len */ - lkey_len = (BTref->attributes & btha_bigKeysMask) - ? get_UINT16BE(* (UINT16BE *)rec_ptr) - : (* (uint8_t *)rec_ptr); - - /* compute offset to data record */ - data_offset = lkey_len + ((BTref->attributes & btha_bigKeysMask) ? 2 : 1); - if (data_offset > rec_len) - /* hurk! */ - return IMGTOOLERR_CORRUPTIMAGE; - /* fix alignment */ - if (data_offset & 1) - data_offset++; - - if (data_ptr) - *data_ptr = (uint8_t *)rec_ptr + data_offset; - if (data_len) - *data_len = (rec_len > data_offset) ? rec_len-data_offset : 0; - - return IMGTOOLERR_SUCCESS; -} - -/* - BT_check - - Check integrity of a complete B-tree - - BTref (I/O): open B-tree file handle - is_extent (I): true if we are opening the extent B-tree (we want to do - extra checks in this case because the extent B-Tree may include extent - records for the extent B-tree itself, and if an extent record for the - extent B-tree is located in an extent that has not been defined by - previous extent records, then we can never retreive this extent record) - - Return imgtool error code -*/ -struct data_nodes_t -{ - void *buf; - uint32_t node_num; - uint32_t cur_rec; - uint32_t num_recs; -}; -static imgtoolerr_t BT_check(mac_BTref *BTref, int is_extent) -{ - uint16_t node_numRecords; - BTHeaderRecord *header_rec; - uint8_t *bitmap; - - data_nodes_t *data_nodes; - int i, j; - uint32_t cur_node, prev_node; - void *rec1, *rec2; - int rec1_len, rec2_len; - void *rec1_data; - int rec1_data_len; - uint32_t totalNodes, lastLeafNode; - uint32_t freeNodes; - int compare_result; - uint32_t map_count, map_len; - uint32_t run_len; - uint32_t run_bit_len; - uint32_t actualFreeNodes; - imgtoolerr_t err; - uint32_t maxExtentAB = 0, maxExtentNode = 0, extentEOL = 0; /* if is_extent is true */ - - if (is_extent) - { - switch (BTref->fileref.l2_img->format) - { - case L2I_MFS: - /* MFS does not feature any extents B-tree! */ - return IMGTOOLERR_UNEXPECTED; - - case L2I_HFS: - maxExtentAB = 0; - for (j=0; j<3; j++) - maxExtentAB += get_UINT16BE(BTref->fileref.hfs.extents[j].numABlks); - maxExtentNode = (uint64_t)maxExtentAB * 512 * BTref->fileref.l2_img->blocksperAB - / BTref->nodeSize; - extentEOL = false; - break; - } - } - - /* read header node */ - if ((! is_extent) || (0 < maxExtentNode)) - err = BT_read_node(BTref, 0, btnk_headerNode, 0, BTref->node_buf); - else - err = IMGTOOLERR_CORRUPTIMAGE; - if (err) - return err; - - /* check we have enough records */ - node_numRecords = get_UINT16BE(((BTNodeHeader *) BTref->node_buf)->numRecords); - if (node_numRecords < 3) - return IMGTOOLERR_CORRUPTIMAGE; - - /* get header record */ - err = BT_node_get_record(BTref, BTref->node_buf, 0, &rec1, &rec1_len); - if (err) - return err; - header_rec = (BTHeaderRecord *)rec1; - - /* check length of header record */ - if (rec1_len < sizeof(BTHeaderRecord)) - return IMGTOOLERR_CORRUPTIMAGE; - - totalNodes = get_UINT32BE(header_rec->totalNodes); - if (totalNodes == 0) - /* we need at least one header node */ - return IMGTOOLERR_CORRUPTIMAGE; - lastLeafNode = get_UINT32BE(header_rec->lastLeafNode); - freeNodes = get_UINT32BE(header_rec->freeNodes); - - /* check file length */ - if ((BTref->nodeSize * totalNodes) > BTref->fileref.pLen) - return IMGTOOLERR_CORRUPTIMAGE; - - /* initialize for the function postlog ("bail:" tag) */ - err = IMGTOOLERR_SUCCESS; - bitmap = NULL; - data_nodes = NULL; - - /* alloc buffer for reconstructed bitmap */ - map_len = (totalNodes + 7) / 8; - bitmap = (uint8_t*)malloc(map_len); - if (! bitmap) - return IMGTOOLERR_OUTOFMEMORY; - memset(bitmap, 0, map_len); - - /* check B-tree data nodes (i.e. index and leaf nodes) */ - if (BTref->treeDepth == 0) - { - /* B-tree is empty */ - if (BTref->rootNode || BTref->firstLeafNode || lastLeafNode) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto bail; - } - } - else - { - /* alloc array of buffers for catalog data nodes */ - data_nodes = (data_nodes_t *)malloc(sizeof(data_nodes_t) * BTref->treeDepth); - if (! data_nodes) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto bail; - } - for (i=0; i<BTref->treeDepth; i++) - data_nodes[i].buf = NULL; /* required for function postlog to work should next loop fail */ - for (i=0; i<BTref->treeDepth; i++) - { - data_nodes[i].buf = malloc(BTref->nodeSize); - if (!data_nodes[i].buf) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto bail; - } - } - - /* read first data nodes */ - cur_node = BTref->rootNode; - for (i=BTref->treeDepth-1; i>=0; i--) - { - /* check node index */ - if (cur_node >= totalNodes) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - /* check that node has not been used for another purpose */ - /* this check is unecessary because the current consistency checks - that forward and back linking match and that node height is correct - are enough to detect such errors */ -#if 0 - if (bitmap[cur_node >> 3] & (0x80 >> (cur_node & 7))) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } -#endif - /* add node in bitmap */ - bitmap[cur_node >> 3] |= (0x80 >> (cur_node & 7)); - /* read node */ - if ((! is_extent) || (cur_node < maxExtentNode)) - err = BT_read_node(BTref, cur_node, i ? btnk_indexNode : btnk_leafNode, i+1, data_nodes[i].buf); - else - err = IMGTOOLERR_CORRUPTIMAGE; - if (err) - goto bail; - /* check that it is the first node at this level */ - if (get_UINT32BE(((BTNodeHeader *) data_nodes[i].buf)->bLink)) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - /* fill other fields */ - data_nodes[i].node_num = cur_node; - data_nodes[i].cur_rec = 0; - data_nodes[i].num_recs = get_UINT16BE(((BTNodeHeader *) data_nodes[i].buf)->numRecords); - /* check that there is at least one record */ - if (data_nodes[i].num_recs == 0) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - - /* iterate to next level if applicable */ - if (i != 0) - { - /* extract first record */ - err = BT_node_get_keyed_record(BTref, data_nodes[i].buf, true, 0, &rec1, &rec1_len); - if (err) - goto bail; - - /* extract record data ptr */ - err = BT_get_keyed_record_data(BTref, rec1, rec1_len, &rec1_data, &rec1_data_len); - if (err) - goto bail; - if (rec1_data_len < sizeof(UINT32BE)) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - - /* iterate to next level */ - cur_node = get_UINT32BE(* (UINT32BE *)rec1_data); - } - } - - /* check that a) the root node has no successor, and b) that we have really - read the first leaf node */ - if (get_UINT32BE(((BTNodeHeader *) data_nodes[BTref->treeDepth-1].buf)->fLink) - || (cur_node != BTref->firstLeafNode)) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - - /* check that keys are ordered correctly */ - while (1) - { - /* iterate through parent nodes */ - i = 0; - while ((i<BTref->treeDepth) && ((data_nodes[i].cur_rec == 0) || (data_nodes[i].cur_rec == data_nodes[i].num_recs))) - { - /* read next node if necessary */ - if (data_nodes[i].cur_rec == data_nodes[i].num_recs) - { - /* get link to next node */ - cur_node = get_UINT32BE(((BTNodeHeader *) data_nodes[i].buf)->fLink); - if (cur_node == 0) - { - if (i == 0) - /* normal End of List */ - goto end_of_list; - else - { - /* error */ - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - } - /* add node in bitmap */ - bitmap[cur_node >> 3] |= (0x80 >> (cur_node & 7)); - /* read node */ - if ((! is_extent) || (cur_node < maxExtentNode)) - err = BT_read_node(BTref, cur_node, i ? btnk_indexNode : btnk_leafNode, i+1, data_nodes[i].buf); - else - err = IMGTOOLERR_CORRUPTIMAGE; - if (err) - goto bail; - /* check that backward linking match forward linking */ - if (get_UINT32BE(((BTNodeHeader *) data_nodes[i].buf)->bLink) != data_nodes[i].node_num) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - /* fill other fields */ - data_nodes[i].node_num = cur_node; - data_nodes[i].cur_rec = 0; - data_nodes[i].num_recs = get_UINT16BE(((BTNodeHeader *) data_nodes[i].buf)->numRecords); - /* check that there is at least one record */ - if (data_nodes[i].num_recs == 0) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - /* next test is not necessary because we have checked that - the root node has no successor */ -#if 0 - if (i < BTref->treeDepth-1) - { -#endif - data_nodes[i+1].cur_rec++; -#if 0 - } - else - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } -#endif - } - i++; - } - - if (is_extent && !extentEOL) - { - /* extract current leaf record and update maxExtentAB and - maxExtentNode */ - hfs_extentKey *extentKey; - hfs_extent *extentData; - - /* extract current leaf record */ - err = BT_node_get_keyed_record(BTref, data_nodes[0].buf, false, data_nodes[0].cur_rec, &rec1, &rec1_len); - if (err) - goto bail; - - extentKey = (hfs_extentKey*)rec1; - if ((extentKey->keyLength < 7) || (extentKey->forkType != 0) || (get_UINT32BE(extentKey->fileID) != 3) - || (get_UINT16BE(extentKey->startBlock) != maxExtentAB)) - /* the key is corrupt or does not concern the extent - B-tree: set the extentEOL flag so that we stop looking for - further extent records for the extent B-tree */ - extentEOL = true; - else - { /* this key concerns the extent B-tree: update maxExtentAB - and maxExtentNode */ - /* extract record data ptr */ - err = BT_get_keyed_record_data(BTref, rec1, rec1_len, &rec1_data, &rec1_data_len); - if (err) - goto bail; - if (rec1_data_len < sizeof(hfs_extent)*3) - /* the record is corrupt: set the extentEOL flag so - that we stop looking for further extent records for the - extent B-tree */ - extentEOL = true; - else - { - extentData = (hfs_extent*)rec1_data; - - for (j=0; j<3; j++) - maxExtentAB += get_UINT16BE(extentData[j].numABlks); - maxExtentNode = (uint64_t)maxExtentAB * 512 * BTref->fileref.l2_img->blocksperAB - / BTref->nodeSize; - } - } - if (extentEOL) - { - /* check that the extent B-Tree has been defined entirely */ - if (maxExtentNode < totalNodes) - { /* no good */ - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - } - } - - if (i<BTref->treeDepth) - { - /* extract current record */ - err = BT_node_get_keyed_record(BTref, data_nodes[i].buf, i > 0, data_nodes[i].cur_rec, &rec1, &rec1_len); - if (err) - goto bail; - - /* extract previous record */ - err = BT_node_get_keyed_record(BTref, data_nodes[i].buf, i > 0, data_nodes[i].cur_rec-1, &rec2, &rec2_len); - if (err) - goto bail; - - /* check that it is sorted correctly */ - compare_result = (*BTref->key_compare_func)(rec1, rec2); - if (compare_result <= 0) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - - i--; - } - else - { - i--; - if (i>0) - { /* extract first record of root if it is an index node */ - err = BT_node_get_keyed_record(BTref, data_nodes[i].buf, true, data_nodes[i].cur_rec, &rec1, &rec1_len); - if (err) - goto bail; - } - i--; - } - - while (i>=0) - { - /* extract first record of current level */ - err = BT_node_get_keyed_record(BTref, data_nodes[i].buf, i > 0, data_nodes[i].cur_rec, &rec2, &rec2_len); - if (err) - goto bail; - - /* compare key with key of current record of upper level */ - compare_result = (*BTref->key_compare_func)(rec1, rec2); - if (compare_result != 0) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - - /* extract record data ptr */ - err = BT_get_keyed_record_data(BTref, rec1, rec1_len, &rec1_data, &rec1_data_len); - if (err) - goto bail; - if (rec1_data_len < sizeof(UINT32BE)) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - cur_node = get_UINT32BE(* (UINT32BE *)rec1_data); - - /* compare node index with data of current record of upper - level */ - if (cur_node != data_nodes[i].node_num) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - - /* iterate to next level */ - rec1 = rec2; - rec1_len = rec2_len; - i--; - } - - /* next leaf record */ - data_nodes[0].cur_rec++; - } - -end_of_list: - /* check that we are at the end of list for each index level */ - for (i=1; i<BTref->treeDepth; i++) - { - if ((data_nodes[i].cur_rec != (data_nodes[i].num_recs-1)) - || get_UINT32BE(((BTNodeHeader *) data_nodes[i].buf)->fLink)) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - } - /* check that the last leaf node is what it is expected to be */ - if (data_nodes[0].node_num != lastLeafNode) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - } - - /* check map node chain */ - cur_node = 0; /* node 0 is the header node... */ - bitmap[0] |= 0x80; - /* check back linking */ - if (get_UINT32BE(((BTNodeHeader *) BTref->node_buf)->bLink)) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - /* get pointer to next node */ - cur_node = get_UINT32BE(((BTNodeHeader *) BTref->node_buf)->fLink); - while (cur_node != 0) - { - /* save node address */ - prev_node = cur_node; - /* check that node has not been used for another purpose */ - /* this check is unecessary because the current consistency checks that - forward and back linking match and that node height is correct are - enough to detect such errors */ -#if 0 - if (bitmap[cur_node >> 3] & (0x80 >> (cur_node & 7))) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } -#endif - /* add node in bitmap */ - bitmap[cur_node >> 3] |= (0x80 >> (cur_node & 7)); - /* read map node */ - if ((! is_extent) || (cur_node < maxExtentNode)) - err = BT_read_node(BTref, cur_node, btnk_mapNode, 0, BTref->node_buf); - else - err = IMGTOOLERR_CORRUPTIMAGE; - if (err) - goto bail; - /* check back linking */ - if (get_UINT32BE(((BTNodeHeader *) BTref->node_buf)->bLink) != prev_node) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - /* get pointer to next node */ - cur_node = get_UINT32BE(((BTNodeHeader *) BTref->node_buf)->fLink); - } - - /* re-read header node */ - err = BT_read_node(BTref, 0, btnk_headerNode, 0, BTref->node_buf); - if (err) - goto bail; - - /* get header bitmap record */ - err = BT_node_get_record(BTref, BTref->node_buf, 2, &rec1, &rec1_len); - if (err) - goto bail; - - /* check bitmap, iterating map nodes */ - map_count = 0; - actualFreeNodes = 0; - while (map_count < map_len) - { - /* compute compare len */ - run_len = rec1_len; - if (run_len > (map_len-map_count)) - run_len = map_len-map_count; - /* check that all used nodes are marked as such in the B-tree bitmap */ - for (i=0; i<run_len; i++) - if (bitmap[map_count+i] & ~((uint8_t *)rec1)[i]) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - /* count free nodes */ - run_bit_len = rec1_len*8; - if (run_bit_len > (totalNodes-map_count*8)) - run_bit_len = totalNodes-map_count*8; - for (i=0; i<run_bit_len; i++) - if (! (((uint8_t *)rec1)[i>>3] & (0x80 >> (i & 7)))) - actualFreeNodes++; - map_count += run_len; - /* read next map node if required */ - if (map_count < map_len) - { - /* get pointer to next node */ - cur_node = get_UINT32BE(((BTNodeHeader *) BTref->node_buf)->fLink); - if (cur_node == 0) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - /* read map node */ - err = BT_read_node(BTref, cur_node, btnk_mapNode, 0, BTref->node_buf); - if (err) - goto bail; - /* get map record */ - err = BT_node_get_record(BTref, BTref->node_buf, 0, &rec1, &rec1_len); - if (err) - goto bail; - header_rec = (BTHeaderRecord *)rec1; - } - } - - /* check free node count */ - if (freeNodes != actualFreeNodes) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - -bail: - /* free buffers */ - if (data_nodes) - { - for (i=0; i<BTref->treeDepth; i++) - if (data_nodes[i].buf) - free(data_nodes[i].buf); - free(data_nodes); - } - if (bitmap) - free(bitmap); - - return err; -} - -/* - BT_search_leaf_rec - - Search for a given key in a B-Tree. If exact match found, returns - corresponding leaf record. Otherwise, may return the greatest record less - than the requested key (of course, this will fail if the key is lower than - all keys in the B-Tree). - - BTref (I/O): open B-tree file handle - search_key (I): key to search the B-Tree for - node_ID (O): set to the node ID of the node the record is located in (may - be NULL) - record_ID (O): set to the index of the record in the node (may be NULL) - record_ptr (O): set to point to record in node buffer (may be NULL) - record_len (O): set to total record len (may be NULL) - search_exact_match (I): if true, the function will search for a record - equal to search_key; if false, the function will search for the - greatest record less than or equal to search_key - match_found (O): set to true if an exact match for search_key has been - found (only makes sense if search_exact_match is false) (may be NULL) - - Return imgtool error code -*/ -static imgtoolerr_t BT_search_leaf_rec(mac_BTref *BTref, const void *search_key, - uint32_t *node_ID, int *record_ID, - void **record_ptr, int *record_len, - int search_exact_match, int *match_found) -{ - imgtoolerr_t err; - int i; - uint32_t cur_node; - void *cur_rec; - int cur_rec_len; - void *last_rec; - int last_rec_len = 0; - void *rec_data; - int rec_data_len; - int depth; - uint16_t node_numRecords; - int compare_result = 0; - - /* start with root node */ - if ((BTref->rootNode == 0) || (BTref->treeDepth == 0)) - /* tree is empty */ - return ((BTref->rootNode == 0) == (BTref->treeDepth == 0)) - ? IMGTOOLERR_FILENOTFOUND - : IMGTOOLERR_CORRUPTIMAGE; - - cur_node = BTref->rootNode; - depth = BTref->treeDepth; - - while (1) - { - /* read current node */ - err = BT_read_node(BTref, cur_node, (depth > 1) ? btnk_indexNode : btnk_leafNode, depth, BTref->node_buf); - if (err) - return err; - - /* search for key */ - node_numRecords = get_UINT16BE(((BTNodeHeader *) BTref->node_buf)->numRecords); - last_rec = cur_rec = NULL; - for (i=0; i<node_numRecords; i++) - { - err = BT_node_get_keyed_record(BTref, BTref->node_buf, depth > 1, i, &cur_rec, &cur_rec_len); - if (err) - return err; - - compare_result = (*BTref->key_compare_func)(cur_rec, search_key); - if (compare_result > 0) - break; - last_rec = cur_rec; - last_rec_len = cur_rec_len; - if (compare_result == 0) - break; - } - - if (! last_rec) - { /* all keys are greater than the search key: the search key is - nowhere in the tree */ - if (search_exact_match) - return IMGTOOLERR_FILENOTFOUND; - - if (match_found) - *match_found = false; - - if (node_ID) - *node_ID = 0; - - if (record_ID) - *record_ID = -1; - - if (record_ptr) - *record_ptr = NULL; - - return IMGTOOLERR_SUCCESS; - } - - if (((BTNodeHeader *) BTref->node_buf)->kind == btnk_leafNode) - /* leaf node -> end of search */ - break; - - /* extract record data ptr */ - err = BT_get_keyed_record_data(BTref, last_rec, last_rec_len, &rec_data, &rec_data_len); - if (err) - return err; - if (rec_data_len < sizeof(UINT32BE)) - return IMGTOOLERR_CORRUPTIMAGE; - - /* iterate to next level */ - cur_node = get_UINT32BE(* (UINT32BE *)rec_data); - depth--; - } - - if (compare_result != 0) - /* key not found */ - if (search_exact_match) - return IMGTOOLERR_FILENOTFOUND; - - if (match_found) - *match_found = (compare_result == 0); - - if (node_ID) - *node_ID = cur_node; - - if (record_ID) - *record_ID = i; - - if (record_ptr) - *record_ptr = last_rec; - - if (record_len) - *record_len = last_rec_len; - - return IMGTOOLERR_SUCCESS; -} - -/* - BT_leaf_rec_enumerator_open - - Open enumerator for leaf records of a B-Tree - - BTref (I/O): open B-tree file handle - enumerator (O): B-Tree enumerator to open - - Return imgtool error code -*/ -static imgtoolerr_t BT_leaf_rec_enumerator_open(mac_BTref *BTref, BT_leaf_rec_enumerator *enumerator) -{ - enumerator->BTref = BTref; - enumerator->cur_node = BTref->firstLeafNode; - enumerator->cur_rec = 0; - - return IMGTOOLERR_SUCCESS; -} - -/* - BT_leaf_rec_enumerator_read - - Read next leaf record of a B-Tree - - enumerator (I/O): open B-Tree enumerator - - Return imgtool error code -*/ -static imgtoolerr_t BT_leaf_rec_enumerator_read(BT_leaf_rec_enumerator *enumerator, void **record_ptr, int *rec_len) -{ - uint16_t node_numRecords; - imgtoolerr_t err; - - - *record_ptr = NULL; - - /* check EOList condition */ - if (enumerator->cur_node == 0) - return IMGTOOLERR_SUCCESS; - - /* read current node */ - err = BT_read_node(enumerator->BTref, enumerator->cur_node, btnk_leafNode, 1, enumerator->BTref->node_buf); - if (err) - return err; - node_numRecords = get_UINT16BE(((BTNodeHeader *) enumerator->BTref->node_buf)->numRecords); - - /* skip nodes until we find a record */ - while ((enumerator->cur_rec >= node_numRecords) && (enumerator->cur_node != 0)) - { - enumerator->cur_node = get_UINT32BE(((BTNodeHeader *) enumerator->BTref->node_buf)->fLink); - enumerator->cur_rec = 0; - - /* read node */ - err = BT_read_node(enumerator->BTref, enumerator->cur_node, btnk_leafNode, 1, enumerator->BTref->node_buf); - if (err) - return err; - node_numRecords = get_UINT16BE(((BTNodeHeader *) enumerator->BTref->node_buf)->numRecords); - } - - /* check EOList condition */ - if (enumerator->cur_node == 0) - return IMGTOOLERR_SUCCESS; - - /* get current record */ - err = BT_node_get_keyed_record(enumerator->BTref, enumerator->BTref->node_buf, false, enumerator->cur_rec, record_ptr, rec_len); - if (err) - return err; - - /* iterate to next record */ - enumerator->cur_rec++; - if (enumerator->cur_rec >= node_numRecords) - { /* iterate to next node if last record (not required, but will improve - performance on next iteration) */ - enumerator->cur_node = get_UINT32BE(((BTNodeHeader *) enumerator->BTref->node_buf)->fLink); - enumerator->cur_rec = 0; - } - return IMGTOOLERR_SUCCESS; -} - -/* - B-Tree extend EOF algorithm: - * see if the bitmap will need to be extended - * extend EOF by min 1 (if bitmap is large engough) or 2 (if bitmap needs - to be extended) and max ClumpSiz (see extClpSiz and ctClpSiz in MDB) - ***If we are extending the extent B-Tree, we need to defer the possible - creation of an additional extent record, or we might enter an endless - recursion loop*** - - Empty node alloc algorithm: - - * see if there is any free node in B-tree bitmap - * optionally, try to compact the B-tree if file is full - * if file is still full, extend EOF and try again - * mark new block as used and return its index - - - Empty node delete algorithm: - - * remove node from link list - * mark node as free in the B-tree bitmap - * optionally, if more than N% of the B-tree is free, compact the B-tree and - free some disk space - * Count nodes on this level; if there is only one left, delete parent index - node and mark the relaining node as root; if it was the last leaf node, - update header node with an empty B-tree; in either case, decrement tree - depth - - - Record shifting algorithm: - - For a given node and its first non-empty successor node: - - * compute how much free room there is in the node - * see if the first record of the first non-empty successor can fit - * if so, move it (i.e. delete the first record of the later node, and add a - copy of it to the end of the former) - - - Node merging algorithm - - * Consider node and its predecessor. If there is room, shift all records - from later to former, then delete empty later node, and delete later - record from parent index node. - - - Node splitting algorithm (non-first) - - * Consider node and its predecessor. Create new middle node and split - records in 3 even sets. Update record for last node and insert record - for middle node in parent index node. - - - Node splitting algorithm (first node) - - * Create new successor node, and split records in 2 1/3 and 2/3 sets. - Insert record for later node in parent index node. - - - Record delete algorithm: - - * remove record from node - * if record was first in node, test if node is now empty - * if node is not empty, substitute key of deleted record with key of - new head record in index tree - * if node is empty, delete key of deleted record in index tree, then - delete empty node - * optionally, look the predecessor node. Merge the two nodes if possible. - - - Record insert algorithm: - - * if there room, just insert new record in node; if new record is in first - position, update record in parent index node - * else consider predecessor: see if we can make enough room by shifting - records. If so, do shift records, insert new record, update record in - parent index node - * else split the nodes and insert record -*/ -/* - Possible additions: - - Node compaction algorithm: - - This algorithm can be executed with a specific start point and max number - of nodes, or with all nodes on a level. - - * see how many nodes we can save by shifting records left - * if we will save at least one node, do shift as many records as possible - (try to leave free space split homogeneously???) -*/ - -/*static void*/ - -#if 0 -#pragma mark - -#pragma mark RESOURCE IMPLEMENTATION -#endif - -/* - Resource manager - - The resource manager stores arbitrary chunks of data (resource) identified - by a type/id pair. The resource type is a 4-char code, which generally - implies the format of the data (e.g. 'PICT' is for a quickdraw picture, - 'STR ' for a macintosh string, 'CODE' for 68k machine code, etc). The - resource id is a signed 16-bit number that uniquely identifies each - resource of a given type. Note that, with most resource types, resources - with id < 128 are system resources that are available to all applications, - whereas resources with id >= 128 are application resources visible only to - the application that defines them. - - Each resource can optionally have a resource name, which is a macintosh - string of 255 chars at most. - - Limits: - 16MBytes of data - 64kbytes of type+reference lists - 64kbytes of resource names - - The Macintosh toolbox can open several resource files simulteanously to - overcome these restrictions. - - Resources are used virtually everywhere in the Macintosh Toolbox, so it is - no surprise that file comments and MFS folders are stored in resource files. -*/ - -/* - Resource header -*/ -struct rsrc_header -{ - UINT32BE data_offs; /* Offset from beginning of resource fork to resource data */ - UINT32BE map_offs; /* Offset from beginning of resource fork to resource map */ - UINT32BE data_len; /* Length of resource data */ - UINT32BE map_len; /* Length of resource map */ -}; - -/* - Resource data: each data entry is preceded by its len (UINT32BE) - Offset to specific data fields are gotten from the resource map -*/ - -/* - Resource map: -*/ -struct rsrc_map_header -{ - rsrc_header reserved0; /* Reserved for copy of resource header */ - UINT32BE reserved1; /* Reserved for handle to next resource map */ - UINT16BE reserved2; /* Reserved for file reference number */ - - UINT16BE attr; /* Resource fork attributes */ - UINT16BE typelist_offs; /* Offset from beginning of map to resource type list */ - UINT16BE namelist_offs; /* Offset from beginning of map to resource name list */ - UINT16BE type_count; /* Number of types in the map minus 1 */ - /* This is actually part of the type list, which matters for offsets */ -}; - -/* - Resource type list entry -*/ -struct rsrc_type_entry -{ - UINT32BE type; /* Resource type */ - UINT16BE ref_count; /* Number of resources of this type in map minus 1 */ - UINT16BE ref_offs; /* Offset from beginning of resource type list to reference list for this type */ -}; - -/* - Resource reference list entry -*/ -struct rsrc_ref_entry -{ - UINT16BE id; /* Resource ID */ - UINT16BE name_offs; /* Offset from beginning of resource name list to resource name */ - /* (-1 if none) */ - uint8_t attr; /* Resource attributes */ - UINT24BE data_offs; /* Offset from beginning of resource data to data for this resource */ - UINT32BE reserved; /* Reserved for handle to resource */ -}; - -/* - Resource name list entry: this is just a standard macintosh string -*/ - -struct mac_resfileref -{ - mac_fileref fileref; /* open resource fork ref (you may open resources - files in data fork, too, if you ever need to, - but Classic MacOS never does such a thing - (MacOS X often does so, though)) */ - uint32_t data_offs; /* Offset from beginning of resource file to resource data */ - uint32_t map_offs; /* Offset from beginning of resource file to resource data */ - - uint16_t typelist_offs; /* Offset from beginning of map to resource type list */ - uint16_t namelist_offs; /* Offset from beginning of map to resource name list */ - uint16_t type_count; /* Number of types in the map minus 1 */ - /* This is actually part of the type list, which matters for offsets */ -}; - -#ifdef UNUSED_FUNCTION -/* - resfile_open - - Open a file as a resource file. The file must be already open as a - macintosh file. - - resfileref (I/O): resource file handle to open (resfileref->fileref must - have been opened previously) - - Return imgtool error code -*/ -static imgtoolerr_t resfile_open(mac_resfileref *resfileref) -{ - imgtoolerr_t err; - rsrc_header header; - rsrc_map_header map_header; - - /* seek to resource header */ - err = mac_file_seek(&resfileref->fileref, 0); - if (err) - return err; - - err = mac_file_read(&resfileref->fileref, sizeof(header), &header); - if (err) - return err; - - resfileref->data_offs = get_UINT32BE(header.data_offs); - resfileref->map_offs = get_UINT32BE(header.map_offs); - - /* seek to resource map header */ - err = mac_file_seek(&resfileref->fileref, resfileref->map_offs); - if (err) - return err; - - err = mac_file_read(&resfileref->fileref, sizeof(map_header), &map_header); - if (err) - return err; - - resfileref->typelist_offs = get_UINT16BE(map_header.typelist_offs); - resfileref->namelist_offs = get_UINT16BE(map_header.namelist_offs); - resfileref->type_count = get_UINT16BE(map_header.type_count); - - return IMGTOOLERR_SUCCESS; -} - -/* - resfile_get_entry - - Get the resource entry in the resource map associated with a given type/id - pair. - - resfileref (I/O): open resource file handle - type (I): type of the resource - id (I): id of the resource - entry (O): resource entry that has been read - - Return imgtool error code -*/ -static imgtoolerr_t resfile_get_entry(mac_resfileref *resfileref, uint32_t type, uint16_t id, rsrc_ref_entry *entry) -{ - imgtoolerr_t err; - rsrc_type_entry type_entry; - uint16_t ref_count; - int i; - - /* seek to resource type list in resource map */ - err = mac_file_seek(&resfileref->fileref, resfileref->map_offs+resfileref->typelist_offs+2); - if (err) - return err; - - if (resfileref->type_count == 0xffff) - /* type list is empty */ - return IMGTOOLERR_FILENOTFOUND; - - for (i=0; i<=resfileref->type_count; i++) - { - err = mac_file_read(&resfileref->fileref, sizeof(type_entry), &type_entry); - if (err) - return err; - if (type == get_UINT32BE(type_entry.type)) - break; - } - if (i > resfileref->type_count) - /* type not found in list */ - return IMGTOOLERR_FILENOTFOUND; - - ref_count = get_UINT16BE(type_entry.ref_count); - - /* seek to resource ref list for this type in resource map */ - err = mac_file_seek(&resfileref->fileref, resfileref->map_offs+resfileref->typelist_offs+get_UINT16BE(type_entry.ref_offs)); - if (err) - return err; - - if (ref_count == 0xffff) - /* ref list is empty */ - return IMGTOOLERR_FILENOTFOUND; - - for (i=0; i<=ref_count; i++) - { - err = mac_file_read(&resfileref->fileref, sizeof(*entry), entry); - if (err) - return err; - if (id == get_UINT16BE(entry->id)) - break; - } - if (i > ref_count) - /* id not found in list */ - return IMGTOOLERR_FILENOTFOUND; - - /* type+id have been found... */ - return IMGTOOLERR_SUCCESS; -} - -/* - resfile_get_resname - - Get the name of a resource. - - resfileref (I/O): open resource file handle - entry (I): resource entry in the resource map (returned by - resfile_get_entry) - string (O): resource name - - Return imgtool error code -*/ -static imgtoolerr_t resfile_get_resname(mac_resfileref *resfileref, const rsrc_ref_entry *entry, mac_str255 string) -{ - imgtoolerr_t err; - uint16_t name_offs; - uint8_t len; - - name_offs = get_UINT16BE(entry->name_offs); - - if (name_offs == 0xffff) - /* ref list is empty */ - return IMGTOOLERR_UNEXPECTED; - - /* seek to resource name in name list in resource map */ - err = mac_file_seek(&resfileref->fileref, resfileref->map_offs+name_offs); - if (err) - return err; - - /* get string length */ - err = mac_file_read(&resfileref->fileref, 1, &len); - if (err) - return err; - - string[0] = len; - - /* get string data */ - err = mac_file_read(&resfileref->fileref, len, string+1); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - -/* - resfile_get_reslen - - Get the data length for a given resource. - - resfileref (I/O): open resource file handle - entry (I): resource entry in the resource map (returned by - resfile_get_entry) - len (O): resource length - - Return imgtool error code -*/ -static imgtoolerr_t resfile_get_reslen(mac_resfileref *resfileref, const rsrc_ref_entry *entry, uint32_t *len) -{ - imgtoolerr_t err; - uint32_t data_offs; - UINT32BE llen; - - data_offs = get_UINT24BE(entry->data_offs); - - /* seek to resource data in resource data section */ - err = mac_file_seek(&resfileref->fileref, resfileref->data_offs+data_offs); - if (err) - return err; - - /* get data length */ - err = mac_file_read(&resfileref->fileref, sizeof(llen), &llen); - if (err) - return err; - - *len = get_UINT32BE(llen); - - return IMGTOOLERR_SUCCESS; -} - -/* - resfile_get_resdata - - Get the data for a given resource. - - resfileref (I/O): open resource file handle - entry (I): resource entry in the resource map (returned by - resfile_get_entry) - offset (I): offset the data should be read from, usually 0 - len (I): length of the data to read, usually the value returned by - resfile_get_reslen - dest (O): resource data - - Return imgtool error code -*/ -static imgtoolerr_t resfile_get_resdata(mac_resfileref *resfileref, const rsrc_ref_entry *entry, uint32_t offset, uint32_t len, void *dest) -{ - imgtoolerr_t err; - uint32_t data_offs; - UINT32BE llen; - - data_offs = get_UINT24BE(entry->data_offs); - - /* seek to resource data in resource data section */ - err = mac_file_seek(&resfileref->fileref, resfileref->data_offs+data_offs); - if (err) - return err; - - /* get data length */ - err = mac_file_read(&resfileref->fileref, sizeof(llen), &llen); - if (err) - return err; - - /* check that we do not ask to read more data than avalaible */ - if ((offset + len) > get_UINT32BE(llen)) - return IMGTOOLERR_UNEXPECTED; - - if (offset) - { /* seek to resource data offset in resource data section */ - err = mac_file_seek(&resfileref->fileref, resfileref->data_offs+data_offs+4+offset); - if (err) - return err; - } - - /* get data */ - err = mac_file_read(&resfileref->fileref, len, dest); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} -#endif - -#if 0 -#pragma mark - -#pragma mark DESKTOP FILE IMPLEMENTATION -#endif -/* - All macintosh volumes have information stored in the desktop file or the - desktop database. - - Such information include file comments, copy of BNDL and FREF resources - that describes supported file types for each application on the volume, - copy of icons for each file type registered by each application on the - volume, etc. On MFS volumes, the list of folders is stored in the desktop - file as well. - - - There have been two implementations of the desktop metadata: - - * The original desktop file. The database is stored in the resource fork - of a (usually invisible) file called "Desktop" (case may change - according to system versions), located at the root of the volume. The - desktop file is used by System 6 and earlier for all volumes (unless - Appleshare 2 is installed and the volume is shared IIRC), and by System - 7 and later for volumes smaller than 2MBytes (so that floppy disks - remain fully compatible with earlier versions of system). The desktop - file is incompletely documented by Apple technote TB06. - - * The desktop database. The database is stored in the resource fork is - stored in the data fork of two (usually invisible) files called - "Desktop DF" and "Desktop DF". The desktop database is used for - volumes shared by Appleshare 2, and for most volumes under System 7 and - later. The format of these file is not documented AFAIK. - - - The reasons for the introduction of the desktop database were: - * the macintosh resource manager cannot share resource files, which was - a problem for Appleshare - * the macintosh resource manager is pretty limited (+/-16MByte of data and - 2727 resources at most), which was a problem for large hard disks with - many programs/comments -*/ - -#ifdef UNUSED_FUNCTION -/* - get_comment - - Get a comment from the Desktop file - - l2_img (I): macintosh image the data should be read from - id (I): comment id (from mfs_hashString(), or HFS FXInfo/DXInfo records) - comment (O): comment that has been read - - Return imgtool error code -*/ -static imgtoolerr_t get_comment(struct mac_l2_imgref *l2_img, uint16_t id, mac_str255 comment) -{ - static const uint8_t desktop_fname[] = {'\7','D','e','s','k','t','o','p'}; - #define restype_FCMT (('F' << 24) | ('C' << 16) | ('M' << 8) | 'T') - mac_resfileref resfileref; - rsrc_ref_entry resentry; - uint32_t reslen; - imgtoolerr_t err; - - /* open rsrc fork of file Desktop in root directory */ - err = mac_file_open(l2_img, 2, desktop_fname, rsrc_fork, &resfileref.fileref); - if (err) - return err; - - /* open resource structures */ - err = resfile_open(&resfileref); - if (err) - return err; - - /* look for resource FCMT #id */ - err = resfile_get_entry(&resfileref, restype_FCMT, id, &resentry); - if (err) - return err; - - /* extract comment len */ - err = resfile_get_reslen(&resfileref, &resentry, &reslen); - if (err) - return err; - - /* check comment len */ - if (reslen > 256) - /* hurk */ - /*return IMGTOOLERR_CORRUPTIMAGE;*/ - /* people willing to extend the MFM comment field (you know, the kind - of masochists that try to support 20-year-old OSes) might append extra - fields, so we just truncate the resource */ - reslen = 256; - - /* extract comment data */ - err = resfile_get_resdata(&resfileref, &resentry, 0, reslen, comment); - if (err) - return err; - - /* phew, we are done! */ - return IMGTOOLERR_SUCCESS; -} -#endif - -#if 0 -#pragma mark - -#pragma mark IMGTOOL MODULE IMPLEMENTATION -#endif - -#ifdef UNUSED_FUNCTION -static void mac_image_exit(imgtool::image *img); -#endif -static void mac_image_info(imgtool::image &img, std::ostream &stream); -static imgtoolerr_t mac_image_beginenum(imgtool::directory &enumeration, const char *path); -static imgtoolerr_t mac_image_nextenum(imgtool::directory &enumeration, imgtool_dirent &ent); -static imgtoolerr_t mac_image_freespace(imgtool::partition &partition, uint64_t *size); -static imgtoolerr_t mac_image_readfile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &destf); -static imgtoolerr_t mac_image_writefile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &sourcef, util::option_resolution *writeoptions); - -#ifdef UNUSED_FUNCTION -/* - close a mfs/hfs image -*/ -static void mac_image_exit(imgtool::image *img) -{ - struct mac_l2_imgref *image = get_imgref(img); - - mac_image_close(image); -} -#endif - -/* - get basic information on a mfs/hfs image - - Currently returns the volume name -*/ -static void mac_image_info(imgtool::image &img, std::ostream &stream) -{ - char buffer[256] = { 0, }; - struct mac_l2_imgref *image = get_imgref(img); - - switch (image->format) - { - case L2I_MFS: - mac_to_c_strncpy(buffer, ARRAY_LENGTH(buffer), image->u.mfs.volname); - break; - - case L2I_HFS: - mac_to_c_strncpy(buffer, ARRAY_LENGTH(buffer), image->u.hfs.volname); - break; - } - - stream << buffer; -} - -/* - MFS/HFS catalog iterator, used when imgtool reads the catalog -*/ -struct mac_iterator -{ - mac_format format; - struct mac_l2_imgref *l2_img; - union - { - struct - { - mfs_dirref dirref; /* open directory reference */ - } mfs; - struct - { - hfs_cat_enumerator catref; /* catalog file enumerator */ - } hfs; - } u; -}; - -/* - Open the disk catalog for enumeration -*/ -static imgtoolerr_t mac_image_beginenum(imgtool::directory &enumeration, const char *path) -{ - struct mac_l2_imgref *image = get_imgref(enumeration.image()); - mac_iterator *iter = (mac_iterator *) enumeration.extra_bytes(); - imgtoolerr_t err = IMGTOOLERR_UNEXPECTED; - - iter->format = image->format; - iter->l2_img = image; - - switch (iter->format) - { - case L2I_MFS: - err = mfs_dir_open(image, path, &iter->u.mfs.dirref); - break; - - case L2I_HFS: - err = hfs_cat_open(image, path, &iter->u.hfs.catref); - break; - } - - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - -/* - Enumerate disk catalog next entry (MFS) -*/ -static imgtoolerr_t mfs_image_nextenum(mac_iterator *iter, imgtool_dirent &ent) -{ - mfs_dir_entry *cur_dir_entry; - imgtoolerr_t err; - - - assert(iter->format == L2I_MFS); - - ent.corrupt = 0; - ent.eof = 0; - - err = mfs_dir_read(&iter->u.mfs.dirref, &cur_dir_entry); - if (err) - { - /* error */ - ent.corrupt = 1; - return err; - } - else if (!cur_dir_entry) - { - /* EOF */ - ent.eof = 1; - return IMGTOOLERR_SUCCESS; - } - - /* copy info */ - mac_to_c_strncpy(ent.filename, ARRAY_LENGTH(ent.filename), cur_dir_entry->name); - ent.filesize = get_UINT32BE(cur_dir_entry->dataPhysicalSize) - + get_UINT32BE(cur_dir_entry->rsrcPhysicalSize); - - return IMGTOOLERR_SUCCESS; -} - -#if 0 -/* - Concatenate path elements in the reverse order - - dest (O): destination buffer - dest_cur_pos (I/O): current position in destination buffer (buffer is - filled from end to start) - dest_max_len (I): length of destination buffer (use length minus one if you - want to preserve a trailing NUL character) - src (I): source C string -*/ -static void concat_fname(char *dest, int *dest_cur_pos, int dest_max_len, const char *src) -{ - static const char ellipsis[] = { '.', '.', '.' }; - int src_len = strlen(src); /* number of chars from src to insert */ - - if (src_len <= *dest_cur_pos) - { - *dest_cur_pos -= src_len; - memcpy(dest + *dest_cur_pos, src, src_len); - } - else - { - memcpy(dest, src + src_len - *dest_cur_pos, *dest_cur_pos); - *dest_cur_pos = 0; - memcpy(dest, ellipsis, (sizeof(ellipsis) <= dest_max_len) - ? sizeof(ellipsis) - : dest_max_len); - } -} -#endif - -/* - Enumerate disk catalog next entry (HFS) -*/ -static imgtoolerr_t hfs_image_nextenum(mac_iterator *iter, imgtool_dirent &ent) -{ - hfs_catKey *catrec_key; - hfs_catData *catrec_data; - uint16_t dataRecType; - imgtoolerr_t err; - /* currently, the mac->C conversion transcodes one mac char with at most 3 - C chars */ - int cur_name_head; - - assert(iter->format == L2I_HFS); - - ent.corrupt = 0; - ent.eof = 0; - - do - { - err = hfs_cat_read(&iter->u.hfs.catref, &catrec_key, &catrec_data); - if (err) - { - /* error */ - ent.corrupt = 1; - return err; - } - else if (!catrec_key) - { - /* EOF */ - ent.eof = 1; - return IMGTOOLERR_SUCCESS; - } - dataRecType = get_UINT16BE(catrec_data->dataType); - } while (((dataRecType != hcrt_Folder) && (dataRecType != hcrt_File)) - || (get_UINT32BE(catrec_key->parID) != iter->u.hfs.catref.parID)); - - /* copy info */ - switch (get_UINT16BE(catrec_data->dataType)) - { - case hcrt_Folder: - ent.directory = 1; - ent.filesize = 0; - break; - - case hcrt_File: - ent.directory = 0; - ent.filesize = get_UINT32BE(catrec_data->file.dataPhysicalSize) - + get_UINT32BE(catrec_data->file.rsrcPhysicalSize); - break; - } - - /* initialize file path buffer */ - cur_name_head = ARRAY_LENGTH(ent.filename); - if (cur_name_head > 0) - { - cur_name_head--; - ent.filename[cur_name_head] = '\0'; - } - - /* insert folder/file name in buffer */ - mac_to_c_strncpy(ent.filename, ARRAY_LENGTH(ent.filename), catrec_key->cName); -// concat_fname(ent.filename, &cur_name_head, ARRAY_LENGTH(ent.filename) - 1, buf); - -#if 0 - /* extract parent directory ID */ - parID = get_UINT32BE(catrec_key->parID); - - /* looping while (parID != 1) will display the volume name; looping while - (parID != 2) won't */ - while (parID != /*1*/2) - { - /* search catalog for folder thread */ - err = hfs_cat_search(iter->l2_img, parID, mac_empty_str, &catrec_key, &catrec_data); - if (err) - { - /* error */ - concat_fname(ent.filename, &cur_name_head, ARRAY_LENGTH(ent.filename) - 1, ":"); - concat_fname(ent.filename, &cur_name_head, ARRAY_LENGTH(ent.filename) - 1, "???"); - - memmove(ent.filename, ent.filename+cur_name_head, ARRAY_LENGTH(ent.filename) - cur_name_head); - ent.corrupt = 1; - return err; - } - - dataRecType = get_UINT16BE(catrec_data->dataType); - - if (dataRecType != hcrt_FolderThread) - { - /* error */ - concat_fname(ent.filename, &cur_name_head, ARRAY_LENGTH(ent.filename)-1, ":"); - concat_fname(ent.filename, &cur_name_head, ARRAY_LENGTH(ent.filename)-1, "???"); - - memmove(ent.filename, ent.filename+cur_name_head, ARRAY_LENGTH(ent.filename)-cur_name_head); - ent.corrupt = 1; - return IMGTOOLERR_CORRUPTIMAGE; - } - - /* got folder thread record: insert the folder name at the start of - file path, then iterate */ - mac_to_c_strncpy(buf, sizeof(buf), catrec_data->thread.nodeName); - concat_fname(ent.filename, &cur_name_head, ARRAY_LENGTH(ent.filename) - 1, ":"); - concat_fname(ent.filename, &cur_name_head, ARRAY_LENGTH(ent.filename) - 1, buf); - - /* extract parent directory ID */ - parID = get_UINT32BE(catrec_data->thread.parID); - } - memmove(ent.filename, ent.filename+cur_name_head, ARRAY_LENGTH(ent.filename) -cur_name_head); -#endif - return IMGTOOLERR_SUCCESS; -} - -/* - Enumerate disk catalog next entry -*/ -static imgtoolerr_t mac_image_nextenum(imgtool::directory &enumeration, imgtool_dirent &ent) -{ - imgtoolerr_t err; - mac_iterator *iter = (mac_iterator *) enumeration.extra_bytes(); - - switch (iter->format) - { - case L2I_MFS: - err = mfs_image_nextenum(iter, ent); - break; - - case L2I_HFS: - err = hfs_image_nextenum(iter, ent); - break; - - default: - assert(1); - err = IMGTOOLERR_UNEXPECTED; - break; - } - return err; -} - -/* - Compute free space on disk image in bytes -*/ -static imgtoolerr_t mac_image_freespace(imgtool::partition &partition, uint64_t *size) -{ - imgtool::image &image(partition.image()); - *size = ((uint64_t) get_imgref(image)->freeABs) * 512; - return IMGTOOLERR_SUCCESS; -} - -#ifdef UNUSED_FUNCTION -static imgtoolerr_t mac_get_comment(struct mac_l2_imgref *image, mac_str255 filename, const mac_dirent *cat_info, mac_str255 comment) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - uint16_t commentID; - - comment[0] = '\0'; - - /* get comment from Desktop file */ - switch (image->format) - { - case L2I_MFS: - commentID = mfs_hashString(filename); - err = get_comment(image, commentID, comment); - break; - - case L2I_HFS: - /* This is the way to get Finder comments in system <= 7. Attached - comments use another method, and Finder 8 uses yet another one. */ - commentID = get_UINT16BE(cat_info->flXFinderInfo.comment); - if (commentID) - err = get_comment(image, commentID, comment); - break; - } - return err; -} -#endif - - -/* - Extract a file from a disk image. -*/ -static imgtoolerr_t mac_image_readfile(imgtool::partition &partition, const char *fpath, const char *fork, imgtool::stream &destf) -{ - imgtoolerr_t err; - imgtool::image &img(partition.image()); - struct mac_l2_imgref *image = get_imgref(img); - uint32_t parID; - mac_str255 filename; - mac_dirent cat_info; - mac_fileref fileref; - uint8_t buf[512]; - uint32_t i, run_len, data_len; - mac_fork_t fork_num; - - err = mac_identify_fork(fork, &fork_num); - if (err) - return err; - - /* resolve path and fetch file info from directory/catalog */ - err = mac_lookup_path(image, fpath, &parID, filename, &cat_info, false); - if (err) - return err; - if (cat_info.dataRecType != hcrt_File) - return IMGTOOLERR_FILENOTFOUND; - - /* open file */ - err = mac_file_open(image, parID, filename, fork_num ? rsrc_fork : data_fork, &fileref); - if (err) - return err; - - data_len = fork_num ? cat_info.rsrcLogicalSize : cat_info.dataLogicalSize; - - /* extract DF */ - i = 0; - while(i < data_len) - { - run_len = std::min(size_t(data_len - i), sizeof(buf)); - - err = mac_file_read(&fileref, run_len, buf); - if (err) - return err; - if (destf.write(buf, run_len) != run_len) - return IMGTOOLERR_WRITEERROR; - i += run_len; - } - - return IMGTOOLERR_SUCCESS; -} - -/* - Add a file to a disk image. -*/ -static imgtoolerr_t mac_image_writefile(imgtool::partition &partition, const char *fpath, const char *fork, imgtool::stream &sourcef, util::option_resolution *writeoptions) -{ - imgtool::image &img(partition.image()); - struct mac_l2_imgref *image = get_imgref(img); - uint32_t parID; - mac_str255 filename; - mac_dirent cat_info; - mac_fileref fileref; - uint32_t fork_len; - /*uint16_t commentID;*/ - /*mac_str255 comment;*/ - uint8_t buf[512]; - uint32_t i, run_len; - imgtoolerr_t err; - mac_fork_t fork_num; - - (void) writeoptions; - - if (image->format == L2I_HFS) - return IMGTOOLERR_UNIMPLEMENTED; - - err = mac_identify_fork(fork, &fork_num); - if (err) - return err; - -#if 0 - if (header.version_old != 0) - return IMGTOOLERR_UNIMPLEMENTED; -#endif - /*mac_strcpy(filename, header.filename);*/ - memset(&cat_info, 0, sizeof(cat_info)); - set_UINT32BE(&cat_info.flFinderInfo.type, 0x3F3F3F3F); - set_UINT32BE(&cat_info.flFinderInfo.creator, 0x3F3F3F3F); - fork_len = sourcef.size(); - /*comment[0] = get_UINT16BE(header.comment_len);*/ /* comment length */ - /* Next two fields are set to 0 with MFS volumes. IIRC, 0 normally - means system script: I don't think MFS stores the file name script code - anywhere on disk, so it should be a reasonable approximation. */ - - /* create file */ - /* clear inited flag and file location in window */ - set_UINT16BE(&cat_info.flFinderInfo.flags, get_UINT16BE(cat_info.flFinderInfo.flags) & ~fif_hasBeenInited); - set_UINT16BE(&cat_info.flFinderInfo.location.v, 0); - set_UINT16BE(&cat_info.flFinderInfo.location.h, 0); - - /* resolve path and create file */ - err = mac_lookup_path(image, fpath, &parID, filename, &cat_info, true); - if (err) - return err; - - /* open file fork */ - err = mac_file_open(image, parID, filename, (fork_num ? rsrc_fork : data_fork), &fileref); - if (err) - return err; - - err = mac_file_seteof(&fileref, fork_len); - if (err) - return err; - - /* extract fork */ - for (i=0; i<fork_len;) - { - run_len = fork_len - i; - if (run_len > 512) - run_len = 512; - if (sourcef.read(buf, run_len) != run_len) - return IMGTOOLERR_READERROR; - err = mac_file_write(&fileref, run_len, buf); - if (err) - return err; - i += run_len; - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t mac_image_listforks(imgtool::partition &partition, const char *path, std::vector<imgtool::fork_entry> &forks) -{ - imgtoolerr_t err; - uint32_t parID; - mac_str255 filename; - mac_dirent cat_info; - imgtool::image &img(partition.image()); - struct mac_l2_imgref *image = get_imgref(img); - - /* resolve path and fetch file info from directory/catalog */ - err = mac_lookup_path(image, path, &parID, filename, &cat_info, false); - if (err) - return err; - if (cat_info.dataRecType != hcrt_File) - return IMGTOOLERR_FILENOTFOUND; - - // specify data fork - forks.emplace_back(cat_info.dataLogicalSize, imgtool::fork_entry::type_t::DATA); - - if (cat_info.rsrcLogicalSize > 0) - { - // specify the resource fork - forks.emplace_back(cat_info.rsrcLogicalSize, imgtool::fork_entry::type_t::RESOURCE); - } - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t mac_image_getattrs(imgtool::partition &partition, const char *path, const uint32_t *attrs, imgtool_attribute *values) -{ - imgtoolerr_t err; - imgtool::image &img(partition.image()); - uint32_t parID; - mac_str255 filename; - mac_dirent cat_info; - struct mac_l2_imgref *image = get_imgref(img); - int i; - - /* resolve path and fetch file info from directory/catalog */ - err = mac_lookup_path(image, path, &parID, filename, &cat_info, false); - if (err) - return err; - if (cat_info.dataRecType != hcrt_File) - return IMGTOOLERR_FILENOTFOUND; - - for (i = 0; attrs[i]; i++) - { - switch(attrs[i]) - { - case IMGTOOLATTR_INT_MAC_TYPE: - values[i].i = get_UINT32BE(cat_info.flFinderInfo.type); - break; - case IMGTOOLATTR_INT_MAC_CREATOR: - values[i].i = get_UINT32BE(cat_info.flFinderInfo.creator); - break; - case IMGTOOLATTR_INT_MAC_FINDERFLAGS: - values[i].i = get_UINT16BE(cat_info.flFinderInfo.flags); - break; - case IMGTOOLATTR_INT_MAC_COORDX: - values[i].i = get_UINT16BE(cat_info.flFinderInfo.location.h); - break; - case IMGTOOLATTR_INT_MAC_COORDY: - values[i].i = get_UINT16BE(cat_info.flFinderInfo.location.v); - break; - case IMGTOOLATTR_INT_MAC_FINDERFOLDER: - values[i].i = get_UINT16BE(cat_info.flFinderInfo.fldr); - break; - case IMGTOOLATTR_INT_MAC_ICONID: - values[i].i = get_UINT16BE(cat_info.flXFinderInfo.iconID); - break; - case IMGTOOLATTR_INT_MAC_SCRIPTCODE: - values[i].i = cat_info.flXFinderInfo.script; - break; - case IMGTOOLATTR_INT_MAC_EXTENDEDFLAGS: - values[i].i = cat_info.flXFinderInfo.XFlags; - break; - case IMGTOOLATTR_INT_MAC_COMMENTID: - values[i].i = get_UINT16BE(cat_info.flXFinderInfo.comment); - break; - case IMGTOOLATTR_INT_MAC_PUTAWAYDIRECTORY: - values[i].i = get_UINT32BE(cat_info.flXFinderInfo.putAway); - break; - - case IMGTOOLATTR_TIME_CREATED: - values[i].t = mac_crack_time(cat_info.createDate).to_time_t(); - break; - case IMGTOOLATTR_TIME_LASTMODIFIED: - values[i].t = mac_crack_time(cat_info.modifyDate).to_time_t(); - break; - } - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t mac_image_setattrs(imgtool::partition &partition, const char *path, const uint32_t *attrs, const imgtool_attribute *values) -{ - imgtoolerr_t err; - uint32_t parID; - mac_str255 filename; - mac_dirent cat_info; - imgtool::image &img(partition.image()); - struct mac_l2_imgref *image = get_imgref(img); - int i; - - /* resolve path and fetch file info from directory/catalog */ - err = mac_lookup_path(image, path, &parID, filename, &cat_info, false); - if (err) - return err; - if (cat_info.dataRecType != hcrt_File) - return IMGTOOLERR_FILENOTFOUND; - - for (i = 0; attrs[i]; i++) - { - switch(attrs[i]) - { - case IMGTOOLATTR_INT_MAC_TYPE: - set_UINT32BE(&cat_info.flFinderInfo.type, values[i].i); - break; - case IMGTOOLATTR_INT_MAC_CREATOR: - set_UINT32BE(&cat_info.flFinderInfo.creator, values[i].i); - break; - case IMGTOOLATTR_INT_MAC_FINDERFLAGS: - set_UINT16BE(&cat_info.flFinderInfo.flags, values[i].i); - break; - case IMGTOOLATTR_INT_MAC_COORDX: - set_UINT16BE(&cat_info.flFinderInfo.location.h, values[i].i); - break; - case IMGTOOLATTR_INT_MAC_COORDY: - set_UINT16BE(&cat_info.flFinderInfo.location.v, values[i].i); - break; - case IMGTOOLATTR_INT_MAC_FINDERFOLDER: - set_UINT16BE(&cat_info.flFinderInfo.fldr, values[i].i); - break; - case IMGTOOLATTR_INT_MAC_ICONID: - set_UINT16BE(&cat_info.flXFinderInfo.iconID, values[i].i); - break; - case IMGTOOLATTR_INT_MAC_SCRIPTCODE: - cat_info.flXFinderInfo.script = values[i].i; - break; - case IMGTOOLATTR_INT_MAC_EXTENDEDFLAGS: - cat_info.flXFinderInfo.XFlags = values[i].i; - break; - case IMGTOOLATTR_INT_MAC_COMMENTID: - set_UINT16BE(&cat_info.flXFinderInfo.comment, values[i].i); - break; - case IMGTOOLATTR_INT_MAC_PUTAWAYDIRECTORY: - set_UINT32BE(&cat_info.flXFinderInfo.putAway, values[i].i); - break; - - case IMGTOOLATTR_TIME_CREATED: - cat_info.createDate = mac_setup_time(values[i].t); - break; - case IMGTOOLATTR_TIME_LASTMODIFIED: - cat_info.modifyDate = mac_setup_time(values[i].t); - break; - } - } - - /* resolve path and fetch file info from directory/catalog */ - err = mac_lookup_path(image, path, &parID, filename, &cat_info, true); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - - -/************************************* - * - * Our very own resource manager - * - *************************************/ - -static const void *mac_walk_resources(const void *resource_fork, size_t resource_fork_length, - uint32_t resource_type, - int (*discriminator)(const void *resource, uint16_t id, uint32_t length, void *param_), - void *param, uint16_t *resource_id, uint32_t *resource_length) -{ - uint32_t resource_data_offset, resource_data_length; - uint32_t resource_map_offset, resource_map_length; - uint32_t resource_typelist_count, resource_typelist_offset; - uint32_t resource_entry_offset, resource_entry_count; - uint32_t i, this_resource_type; - uint32_t this_resource_data, this_resource_length; - uint16_t this_resource_id; - const void *this_resource_ptr; - - if (resource_fork_length < 16) - return NULL; - - /* read resource header; its ok if anything past this point fails */ - resource_data_offset = pick_integer_be(resource_fork, 0, 4); - resource_map_offset = pick_integer_be(resource_fork, 4, 4); - resource_data_length = pick_integer_be(resource_fork, 8, 4); - resource_map_length = pick_integer_be(resource_fork, 12, 4); - if ((resource_data_offset + resource_data_length) > resource_fork_length) - return NULL; - if ((resource_map_offset + resource_map_length) > resource_fork_length) - return NULL; - if (resource_map_length < 30) - return NULL; - - /* read resource map and locate the resource type list */ - resource_typelist_offset = pick_integer_be(resource_fork, - resource_map_offset + 24, 2) + resource_map_offset; - if ((resource_typelist_offset + 2) > resource_fork_length) - return NULL; - resource_typelist_count = pick_integer_be(resource_fork, - resource_typelist_offset, 2) + 1; - if ((resource_typelist_offset + resource_typelist_count * 16 + 2) > resource_fork_length) - return NULL; - - /* scan the resource type list and locate the entries for this type */ - resource_entry_count = 0; - resource_entry_offset = 0; - for (i = 0; i < resource_typelist_count; i++) - { - this_resource_type = pick_integer_be(resource_fork, resource_typelist_offset - + (i * 8) + 2 + 0, 4); - if (this_resource_type == resource_type) - { - resource_entry_count = pick_integer_be(resource_fork, resource_typelist_offset - + (i * 8) + 2 + 4, 2) + 1; - resource_entry_offset = pick_integer_be(resource_fork, resource_typelist_offset - + (i * 8) + 2 + 6, 2) + resource_typelist_offset; - break; - } - } - - /* scan the resource entries, and find the correct resource */ - for (i = 0; i < resource_entry_count; i++) - { - this_resource_id = pick_integer_be(resource_fork, resource_entry_offset - + (i * 12) + 0, 2); - this_resource_data = pick_integer_be(resource_fork, resource_entry_offset - + (i * 12) + 5, 3) + resource_data_offset; - if ((this_resource_data + 4) > resource_fork_length) - return NULL; - - /* gauge the length */ - this_resource_length = pick_integer_be(resource_fork, this_resource_data, 4); - this_resource_data += 4; - if ((this_resource_data + this_resource_length) > resource_fork_length) - return NULL; - - this_resource_ptr = ((const uint8_t *) resource_fork) + this_resource_data; - if (discriminator(this_resource_ptr, this_resource_id, - this_resource_length, param)) - { - if (resource_length) - *resource_length = this_resource_length; - if (resource_id) - *resource_id = this_resource_id; - return this_resource_ptr; - } - } - - return NULL; -} - - - -static int get_resource_discriminator(const void *resource, uint16_t id, uint32_t length, void *param) -{ - const uint16_t *id_ptr = (const uint16_t *) param; - return id == *id_ptr; -} - - - -static const void *mac_get_resource(const void *resource_fork, size_t resource_fork_length, - uint32_t resource_type, uint16_t resource_id, uint32_t *resource_length) -{ - return mac_walk_resources(resource_fork, resource_fork_length, - resource_type, get_resource_discriminator, &resource_id, NULL, resource_length); -} - - - -/************************************* - * - * Custom icons - * - *************************************/ - -static int bundle_discriminator(const void *resource, uint16_t id, uint32_t length, void *param) -{ - uint32_t this_creator_code = pick_integer_be(resource, 0, 4); - uint32_t desired_creator_code = *((uint32_t *) param); - return this_creator_code == desired_creator_code; -} - - - -static uint8_t get_pixel(const uint8_t *src, int width, int height, int bpp, - int x, int y) -{ - uint8_t byte, mask; - int bit_position; - - byte = src[(y * width + x) * bpp / 8]; - bit_position = 8 - ((x % (8 / bpp)) + 1) * bpp; - mask = (1 << bpp) - 1; - return (byte >> bit_position) & mask; -} - - - -static bool load_icon(uint32_t *dest, const void *resource_fork, uint64_t resource_fork_length, - uint32_t resource_type, uint16_t resource_id, int width, int height, int bpp, - const uint32_t *palette, bool has_mask) -{ - bool success = false; - uint32_t frame_length = width * height * bpp / 8; - uint32_t total_length = frame_length * (has_mask ? 2 : 1); - uint32_t resource_length; - - // attempt to fetch resource - const uint8_t *src = (const uint8_t*)mac_get_resource(resource_fork, resource_fork_length, resource_type, - resource_id, &resource_length); - if (src && (resource_length == total_length)) - { - for (int y = 0; y < height; y++) - { - for (int x = 0; x < width; x ++) - { - // check the color - uint8_t color = get_pixel(src, width, height, bpp, x, y); - - // then check the mask - bool is_masked = has_mask - ? get_pixel(src + frame_length, width, height, bpp, x, y) != 0 - : dest[y * width + x] >= 0x80000000; - - // is this actually masked? (note there is a special case when bpp == 1; Mac B&W icons - // had a XOR effect, and this cannot be blocked by the mask) - uint32_t pixel; - if (is_masked || (color && bpp == 1)) - { - // mask is ok; check the actual icon - pixel = palette[color] | 0xFF000000; - } - else - { - // masked out; nothing - pixel = 0x00000000; - } - - dest[y * width + x] = pixel; - } - } - success = true; - } - return success; -} - - - -static imgtoolerr_t mac_image_geticoninfo(imgtool::partition &partition, const char *path, imgtool_iconinfo *iconinfo) -{ - static const uint32_t mac_palette_1bpp[2] = { 0xFFFFFF, 0x000000 }; - - static const uint32_t mac_palette_4bpp[16] = - { - 0xFFFFFF, 0xFCF305, 0xFF6402, 0xDD0806, 0xF20884, 0x4600A5, - 0x0000D4, 0x02ABEA, 0x1FB714, 0x006411, 0x562C05, 0x90713A, - 0xC0C0C0, 0x808080, 0x404040, 0x000000 - }; - - static const uint32_t mac_palette_8bpp[256] = - { - 0xFFFFFF, 0xFFFFCC, 0xFFFF99, 0xFFFF66, 0xFFFF33, 0xFFFF00, - 0xFFCCFF, 0xFFCCCC, 0xFFCC99, 0xFFCC66, 0xFFCC33, 0xFFCC00, - 0xFF99FF, 0xFF99CC, 0xFF9999, 0xFF9966, 0xFF9933, 0xFF9900, - 0xFF66FF, 0xFF66CC, 0xFF6699, 0xFF6666, 0xFF6633, 0xFF6600, - 0xFF33FF, 0xFF33CC, 0xFF3399, 0xFF3366, 0xFF3333, 0xFF3300, - 0xFF00FF, 0xFF00CC, 0xFF0099, 0xFF0066, 0xFF0033, 0xFF0000, - 0xCCFFFF, 0xCCFFCC, 0xCCFF99, 0xCCFF66, 0xCCFF33, 0xCCFF00, - 0xCCCCFF, 0xCCCCCC, 0xCCCC99, 0xCCCC66, 0xCCCC33, 0xCCCC00, - 0xCC99FF, 0xCC99CC, 0xCC9999, 0xCC9966, 0xCC9933, 0xCC9900, - 0xCC66FF, 0xCC66CC, 0xCC6699, 0xCC6666, 0xCC6633, 0xCC6600, - 0xCC33FF, 0xCC33CC, 0xCC3399, 0xCC3366, 0xCC3333, 0xCC3300, - 0xCC00FF, 0xCC00CC, 0xCC0099, 0xCC0066, 0xCC0033, 0xCC0000, - 0x99FFFF, 0x99FFCC, 0x99FF99, 0x99FF66, 0x99FF33, 0x99FF00, - 0x99CCFF, 0x99CCCC, 0x99CC99, 0x99CC66, 0x99CC33, 0x99CC00, - 0x9999FF, 0x9999CC, 0x999999, 0x999966, 0x999933, 0x999900, - 0x9966FF, 0x9966CC, 0x996699, 0x996666, 0x996633, 0x996600, - 0x9933FF, 0x9933CC, 0x993399, 0x993366, 0x993333, 0x993300, - 0x9900FF, 0x9900CC, 0x990099, 0x990066, 0x990033, 0x990000, - 0x66FFFF, 0x66FFCC, 0x66FF99, 0x66FF66, 0x66FF33, 0x66FF00, - 0x66CCFF, 0x66CCCC, 0x66CC99, 0x66CC66, 0x66CC33, 0x66CC00, - 0x6699FF, 0x6699CC, 0x669999, 0x669966, 0x669933, 0x669900, - 0x6666FF, 0x6666CC, 0x666699, 0x666666, 0x666633, 0x666600, - 0x6633FF, 0x6633CC, 0x663399, 0x663366, 0x663333, 0x663300, - 0x6600FF, 0x6600CC, 0x660099, 0x660066, 0x660033, 0x660000, - 0x33FFFF, 0x33FFCC, 0x33FF99, 0x33FF66, 0x33FF33, 0x33FF00, - 0x33CCFF, 0x33CCCC, 0x33CC99, 0x33CC66, 0x33CC33, 0x33CC00, - 0x3399FF, 0x3399CC, 0x339999, 0x339966, 0x339933, 0x339900, - 0x3366FF, 0x3366CC, 0x336699, 0x336666, 0x336633, 0x336600, - 0x3333FF, 0x3333CC, 0x333399, 0x333366, 0x333333, 0x333300, - 0x3300FF, 0x3300CC, 0x330099, 0x330066, 0x330033, 0x330000, - 0x00FFFF, 0x00FFCC, 0x00FF99, 0x00FF66, 0x00FF33, 0x00FF00, - 0x00CCFF, 0x00CCCC, 0x00CC99, 0x00CC66, 0x00CC33, 0x00CC00, - 0x0099FF, 0x0099CC, 0x009999, 0x009966, 0x009933, 0x009900, - 0x0066FF, 0x0066CC, 0x006699, 0x006666, 0x006633, 0x006600, - 0x0033FF, 0x0033CC, 0x003399, 0x003366, 0x003333, 0x003300, - 0x0000FF, 0x0000CC, 0x000099, 0x000066, 0x000033, 0xEE0000, - 0xDD0000, 0xBB0000, 0xAA0000, 0x880000, 0x770000, 0x550000, - 0x440000, 0x220000, 0x110000, 0x00EE00, 0x00DD00, 0x00BB00, - 0x00AA00, 0x008800, 0x007700, 0x005500, 0x004400, 0x002200, - 0x001100, 0x0000EE, 0x0000DD, 0x0000BB, 0x0000AA, 0x000088, - 0x000077, 0x000055, 0x000044, 0x000022, 0x000011, 0xEEEEEE, - 0xDDDDDD, 0xBBBBBB, 0xAAAAAA, 0x888888, 0x777777, 0x555555, - 0x444444, 0x222222, 0x111111, 0x000000 - }; - - static const uint32_t attrs[4] = - { - IMGTOOLATTR_INT_MAC_TYPE, - IMGTOOLATTR_INT_MAC_CREATOR, - IMGTOOLATTR_INT_MAC_FINDERFLAGS - }; - - imgtoolerr_t err; - imgtool_attribute attr_values[3]; - uint32_t type_code, creator_code, finder_flags; - imgtool::stream::ptr stream; - const void *resource_fork; - uint64_t resource_fork_length; - const void *bundle; - uint32_t bundle_length, pos, fref_pos, icn_pos, i; - uint16_t local_id = 0, resource_id; - uint32_t fref_bundleentry_length, icn_bundleentry_length; - const void *fref; - uint32_t resource_length; - - assert((ARRAY_LENGTH(attrs) - 1) - == ARRAY_LENGTH(attr_values)); - - /* first retrieve type and creator code */ - err = mac_image_getattrs(partition, path, attrs, attr_values); - if (err) - return err; - type_code = (uint32_t) attr_values[0].i; - creator_code = (uint32_t) attr_values[1].i; - finder_flags = (uint32_t) attr_values[2].i; - - /* check the bundle bit; if clear (and the type is not 'APPL'), use the - * desktop file */ - if (!(finder_flags & 0x2000) && (type_code != /* APPL */ 0x4150504C)) - path = "Desktop\0"; - - stream = imgtool::stream::open_mem(NULL, 0); - if (!stream) - return IMGTOOLERR_SUCCESS; - - /* read in the resource fork */ - err = mac_image_readfile(partition, path, "RESOURCE_FORK", *stream); - if (err) - return err; - resource_fork = stream->getptr(); - resource_fork_length = stream->size(); - - /* attempt to look up the bundle */ - bundle = mac_walk_resources(resource_fork, resource_fork_length, /* BNDL */ 0x424E444C, - bundle_discriminator, &creator_code, NULL, &bundle_length); - if (!bundle) - return err; - - /* find the FREF and the icon family */ - pos = 8; - fref_pos = icn_pos = 0; - fref_bundleentry_length = icn_bundleentry_length = 0; - while((pos + 10) <= bundle_length) - { - uint32_t this_bundleentry_type = pick_integer_be(bundle, pos + 0, 4); - uint32_t this_bundleentry_length = pick_integer_be(bundle, pos + 4, 2) + 1; - - if (this_bundleentry_type == /* FREF */ 0x46524546) - { - fref_pos = pos; - fref_bundleentry_length = this_bundleentry_length; - } - if (this_bundleentry_type == /* ICN# */ 0x49434E23) - { - icn_pos = pos; - icn_bundleentry_length = this_bundleentry_length; - } - pos += 6 + this_bundleentry_length * 4; - } - if (!fref_pos || !icn_pos) - return err; - - /* look up the FREF */ - for (i = 0; i < fref_bundleentry_length; i++) - { - local_id = pick_integer_be(bundle, fref_pos + (i * 4) + 6, 2); - resource_id = pick_integer_be(bundle, fref_pos + (i * 4) + 8, 2); - - fref = mac_get_resource(resource_fork, resource_fork_length, - /* FREF */ 0x46524546, resource_id, &resource_length); - if (fref && (resource_length >= 7)) - { - if (pick_integer_be(fref, 0, 4) == type_code) - break; - } - } - if (i >= fref_bundleentry_length) - return err; - - /* now look up the icon family */ - resource_id = 0; - for (i = 0; i < icn_bundleentry_length; i++) - { - if (pick_integer_be(bundle, icn_pos + (i * 4) + 6, 2) == local_id) - { - resource_id = pick_integer_be(bundle, icn_pos + (i * 4) + 8, 2); - break; - } - } - if (i >= icn_bundleentry_length) - return err; - - /* fetch 32x32 icons (ICN#, icl4, icl8) */ - if (load_icon((uint32_t *) iconinfo->icon32x32, resource_fork, resource_fork_length, - /* ICN# */ 0x49434E23, resource_id, 32, 32, 1, mac_palette_1bpp, true)) - { - iconinfo->icon32x32_specified = 1; - - load_icon((uint32_t *) iconinfo->icon32x32, resource_fork, resource_fork_length, - /* icl4 */ 0x69636C34, resource_id, 32, 32, 4, mac_palette_4bpp, false); - load_icon((uint32_t *) iconinfo->icon32x32, resource_fork, resource_fork_length, - /* icl8 */ 0x69636C38, resource_id, 32, 32, 8, mac_palette_8bpp, false); - } - - /* fetch 16x16 icons (ics#, ics4, ics8) */ - if (load_icon((uint32_t *) iconinfo->icon16x16, resource_fork, resource_fork_length, - /* ics# */ 0x69637323, resource_id, 16, 16, 1, mac_palette_1bpp, true)) - { - iconinfo->icon16x16_specified = 1; - - load_icon((uint32_t *) iconinfo->icon32x32, resource_fork, resource_fork_length, - /* ics4 */ 0x69637334, resource_id, 32, 32, 4, mac_palette_4bpp, false); - load_icon((uint32_t *) iconinfo->icon32x32, resource_fork, resource_fork_length, - /* ics8 */ 0x69637338, resource_id, 32, 32, 8, mac_palette_8bpp, false); - } - - return err; -} - - - -/************************************* - * - * File transfer suggestions - * - *************************************/ - -static imgtoolerr_t mac_image_suggesttransfer(imgtool::partition &partition, const char *path, imgtool_transfer_suggestion *suggestions, size_t suggestions_length) -{ - imgtoolerr_t err; - uint32_t parID; - mac_str255 filename; - mac_dirent cat_info; - imgtool::image &img(partition.image()); - struct mac_l2_imgref *image = get_imgref(img); - mac_filecategory_t file_category = MAC_FILECATEGORY_DATA; - - if (path) - { - /* resolve path and fetch file info from directory/catalog */ - err = mac_lookup_path(image, path, &parID, filename, &cat_info, false); - if (err) - return err; - if (cat_info.dataRecType != hcrt_File) - return IMGTOOLERR_FILENOTFOUND; - - file_category = (cat_info.rsrcLogicalSize > 0) ? MAC_FILECATEGORY_FORKED : MAC_FILECATEGORY_DATA; - } - - mac_suggest_transfer(file_category, suggestions, suggestions_length); - return IMGTOOLERR_SUCCESS; -} - - - -/************************************* -* -* MacOS Roman Conversion -* -*************************************/ - -static const char32_t macos_roman_code_page[128] = -{ - // 0x80 - 0x8F - 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1, 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8, - // 0x90 - 0x9F - 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3, 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC, - // 0xA0 - 0xAF - 0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF, 0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8, - // 0xB0 - 0xBF - 0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211, 0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x00E6, 0x00F8, - // 0xC0 - 0xCF - 0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB, 0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153, - // 0xD0 - 0xDF - 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA, 0x00FF, 0x0178, 0x2044, 0x20AC, 0x2039, 0x203A, 0xFB01, 0xFB02, - // 0xE0 - 0xEF - 0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1, 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4, - // 0xF0 - 0xFF - 0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC, 0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7 -}; - -static imgtool::simple_charconverter charconverter_macos_roman(macos_roman_code_page); - - -/************************************* - * - * Module population - * - *************************************/ - -static void generic_mac_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info) -{ - switch(state) - { - /* --- the following bits of info are returned as 64-bit signed integers --- */ - case IMGTOOLINFO_INT_OPEN_IS_STRICT: info->i = 1; break; - case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES: info->i = sizeof(struct mac_l2_imgref); break; - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(struct mac_iterator); break; - case IMGTOOLINFO_INT_PATH_SEPARATOR: info->i = ':'; break; - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - case IMGTOOLINFO_STR_FILE: strcpy(info->s = imgtool_temp_str(), __FILE__); break; - case IMGTOOLINFO_STR_EOLN: strcpy(info->s = imgtool_temp_str(), "\r"); 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_CLOSE: /* info->close = mac_image_exit */; break; - case IMGTOOLINFO_PTR_INFO: info->info = mac_image_info; break; - case IMGTOOLINFO_PTR_BEGIN_ENUM: info->begin_enum = mac_image_beginenum; break; - case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = mac_image_nextenum; break; - case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = mac_image_freespace; break; - case IMGTOOLINFO_PTR_READ_FILE: info->read_file = mac_image_readfile; break; - case IMGTOOLINFO_PTR_LIST_FORKS: info->list_forks = mac_image_listforks; break; - case IMGTOOLINFO_PTR_GET_ATTRS: info->get_attrs = mac_image_getattrs; break; - case IMGTOOLINFO_PTR_SET_ATTRS: info->set_attrs = mac_image_setattrs; break; - case IMGTOOLINFO_PTR_GET_ICON_INFO: info->get_iconinfo = mac_image_geticoninfo; break; - case IMGTOOLINFO_PTR_SUGGEST_TRANSFER: info->suggest_transfer = mac_image_suggesttransfer; break; - case IMGTOOLINFO_PTR_FLOPPY_FORMAT: info->p = (void *) floppyoptions_apple35_mac; break; - case IMGTOOLINFO_PTR_CHARCONVERTER: info->charconverter = &charconverter_macos_roman; break; - } -} - - - -void mac_mfs_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info) -{ - switch(state) - { - /* --- the following bits of info are returned as NULL-terminated strings --- */ - case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "mac_mfs"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "Mac MFS Floppy"); break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case IMGTOOLINFO_PTR_FLOPPY_CREATE: info->create = mfs_image_create; break; - case IMGTOOLINFO_PTR_FLOPPY_OPEN: info->open = mfs_image_open; break; - case IMGTOOLINFO_PTR_WRITE_FILE: info->write_file = mac_image_writefile; break; - - default: generic_mac_get_info(imgclass, state, info); break; - } -} - - - -void mac_hfs_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info) -{ - switch(state) - { - /* --- the following bits of info are returned as NULL-terminated strings --- */ - case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "mac_hfs"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "Mac HFS Floppy"); break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case IMGTOOLINFO_PTR_FLOPPY_OPEN: info->open = hfs_image_open; break; - - default: generic_mac_get_info(imgclass, state, info); break; - } -} diff --git a/src/tools/imgtool/modules/macbin.cpp b/src/tools/imgtool/modules/macbin.cpp deleted file mode 100644 index 30400dffdbb..00000000000 --- a/src/tools/imgtool/modules/macbin.cpp +++ /dev/null @@ -1,381 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Raphael Nabet -/**************************************************************************** - - macbin.cpp - - MacBinary filter for use with Mac and ProDOS drivers - -***************************************************************************** - - MacBinary file format - - Offset Length Description - ------ ------ ----------- - 0 1 [I] Magic byte (0x00) - 1 64 [I] File name (Pascal String) - 65 4 [I] File Type Code - 69 4 [I] File Creator Code - 73 1 [I] Finder Flags (bits 15-8) - 74 1 [I] Magic byte (0x00) - 75 2 [I] File Vertical Position - 77 2 [I] File Horizontal Position - 79 2 [I] Window/Folder ID - 81 1 [I] Protected (bit 0) - 82 1 [I] Magic byte (0x00) - 83 4 [I] Data Fork Length - 87 4 [I] Resource Fork Length - 91 4 [I] Creation Date - 95 4 [I] Last Modified Date - 99 2 [I] "Get Info" comment length - 101 1 [II] Finder Flags (bits 7-0) - 102 4 [III] MacBinary III Signature 'mBIN' - 106 1 [III] Script of Filename - 107 1 [III] Extended Finder Flags - 116 4 [II] Unpacked Length - 120 2 [II] Secondary Header Length - 122 1 [II] MacBinary II Version Number (II: 0x81, III: 0x82) - 123 1 [II] Minimum Compatible MacBinary II Version Number (0x81) - 124 2 [II] CRC of previous 124 bytes - - For more information, consult http://www.lazerware.com/formats/macbinary.html - - TODO: I believe that the script code is some sort of identifier identifying - the character set used for the filename. If this is true, we are not - handling that properly - -*****************************************************************************/ - -#include <string.h> - -#include "imgtool.h" -#include "formats/imageutl.h" -#include "macutil.h" - - - -static uint32_t pad128(uint32_t length) -{ - if (length % 128) - length += 128 - (length % 128); - return length; -} - - - -static imgtoolerr_t macbinary_readfile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &destf) -{ - static const uint32_t attrs[] = - { - IMGTOOLATTR_TIME_CREATED, - IMGTOOLATTR_TIME_LASTMODIFIED, - IMGTOOLATTR_INT_MAC_TYPE, - IMGTOOLATTR_INT_MAC_CREATOR, - IMGTOOLATTR_INT_MAC_FINDERFLAGS, - IMGTOOLATTR_INT_MAC_COORDX, - IMGTOOLATTR_INT_MAC_COORDY, - IMGTOOLATTR_INT_MAC_FINDERFOLDER, - IMGTOOLATTR_INT_MAC_SCRIPTCODE, - IMGTOOLATTR_INT_MAC_EXTENDEDFLAGS, - 0 - }; - imgtoolerr_t err; - uint8_t header[128]; - const char *basename; - - uint32_t type_code = 0x3F3F3F3F; - uint32_t creator_code = 0x3F3F3F3F; - uint16_t finder_flags = 0; - uint16_t coord_x = 0; - uint16_t coord_y = 0; - uint16_t finder_folder = 0; - uint8_t script_code = 0; - uint8_t extended_flags = 0; - - uint32_t creation_time = 0; - uint32_t lastmodified_time = 0; - imgtool_attribute attr_values[10]; - - // get the forks - std::vector<imgtool::fork_entry> fork_entries; - err = partition.list_file_forks(filename, fork_entries); - if (err) - return err; - - const imgtool::fork_entry *data_fork = nullptr; - const imgtool::fork_entry *resource_fork = nullptr; - for (const auto &entry : fork_entries) - { - switch (entry.type()) - { - case imgtool::fork_entry::type_t::DATA: - data_fork = &entry; - break; - case imgtool::fork_entry::type_t::RESOURCE: - resource_fork = &entry; - break; - default: - // do nothing - break; - } - } - - /* get the attributes */ - err = partition.get_file_attributes(filename, attrs, attr_values); - if (err && (ERRORCODE(err) != IMGTOOLERR_UNIMPLEMENTED)) - return err; - if (err == IMGTOOLERR_SUCCESS) - { - creation_time = mac_setup_time(attr_values[0].t); - lastmodified_time = mac_setup_time(attr_values[1].t); - type_code = attr_values[2].i; - creator_code = attr_values[3].i; - finder_flags = attr_values[4].i; - coord_x = attr_values[5].i; - coord_y = attr_values[6].i; - finder_folder = attr_values[7].i; - script_code = attr_values[8].i; - extended_flags = attr_values[9].i; - } - - memset(header, 0, sizeof(header)); - - /* place filename */ - basename = filename; - while(basename[strlen(basename) + 1]) - basename += strlen(basename) + 1; - pascal_from_c_string((unsigned char *) &header[1], 64, basename); - - place_integer_be(header, 65, 4, type_code); - place_integer_be(header, 69, 4, creator_code); - place_integer_be(header, 73, 1, (finder_flags >> 8) & 0xFF); - place_integer_be(header, 75, 2, coord_x); - place_integer_be(header, 77, 2, coord_y); - place_integer_be(header, 79, 2, finder_folder); - place_integer_be(header, 83, 4, data_fork ? data_fork->size() : 0); - place_integer_be(header, 87, 4, resource_fork ? resource_fork->size() : 0); - place_integer_be(header, 91, 4, creation_time); - place_integer_be(header, 95, 4, lastmodified_time); - place_integer_be(header, 101, 1, (finder_flags >> 0) & 0xFF); - place_integer_be(header, 102, 4, 0x6D42494E); - place_integer_be(header, 106, 1, script_code); - place_integer_be(header, 107, 1, extended_flags); - place_integer_be(header, 122, 1, 0x82); - place_integer_be(header, 123, 1, 0x81); - place_integer_be(header, 124, 2, ccitt_crc16(0, header, 124)); - - destf.write(header, sizeof(header)); - - if (data_fork) - { - err = partition.read_file(filename, "", destf, NULL); - if (err) - return err; - - destf.fill(0, pad128(data_fork->size())); - } - - if (resource_fork) - { - err = partition.read_file(filename, "RESOURCE_FORK", destf, NULL); - if (err) - return err; - - destf.fill(0, pad128(resource_fork->size())); - } - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t write_fork(imgtool::partition &partition, const char *filename, const char *fork, - imgtool::stream &sourcef, uint64_t pos, uint64_t fork_len, util::option_resolution *opts) -{ - imgtoolerr_t err; - imgtool::stream::ptr mem_stream; - size_t len; - - if (fork_len > 0) - { - mem_stream = imgtool::stream::open_mem(nullptr, 0); - if (!mem_stream) - return IMGTOOLERR_OUTOFMEMORY; - - sourcef.seek(pos, SEEK_SET); - len = imgtool::stream::transfer(*mem_stream, sourcef, fork_len); - if (len < fork_len) - mem_stream->fill(0, fork_len); - - mem_stream->seek(0, SEEK_SET); - err = partition.write_file(filename, fork, *mem_stream, opts, NULL); - if (err) - return err; - } - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t macbinary_writefile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &sourcef, util::option_resolution *opts) -{ - static const uint32_t attrs[] = - { - IMGTOOLATTR_TIME_CREATED, - IMGTOOLATTR_TIME_LASTMODIFIED, - IMGTOOLATTR_INT_MAC_TYPE, - IMGTOOLATTR_INT_MAC_CREATOR, - IMGTOOLATTR_INT_MAC_FINDERFLAGS, - IMGTOOLATTR_INT_MAC_COORDX, - IMGTOOLATTR_INT_MAC_COORDY, - IMGTOOLATTR_INT_MAC_FINDERFOLDER, - IMGTOOLATTR_INT_MAC_SCRIPTCODE, - IMGTOOLATTR_INT_MAC_EXTENDEDFLAGS, - 0 - }; - imgtoolerr_t err; - imgtool::image *image = &partition.image(); - uint8_t header[128]; - uint32_t datafork_size; - uint32_t resourcefork_size; - uint64_t total_size; - uint32_t creation_time; - uint32_t lastmodified_time; - //int version; - imgtool_attribute attr_values[10]; - - uint32_t type_code; - uint32_t creator_code; - uint16_t finder_flags; - uint16_t coord_x; - uint16_t coord_y; - uint16_t finder_folder; - uint8_t script_code = 0; - uint8_t extended_flags = 0; - - /* read in the header */ - memset(header, 0, sizeof(header)); - sourcef.read(header, sizeof(header)); - - /* check magic and zero fill bytes */ - if (header[0] != 0x00) - return IMGTOOLERR_CORRUPTFILE; - if (header[74] != 0x00) - return IMGTOOLERR_CORRUPTFILE; - if (header[82] != 0x00) - return IMGTOOLERR_CORRUPTFILE; - - datafork_size = pick_integer_be(header, 83, 4); - resourcefork_size = pick_integer_be(header, 87, 4); - total_size = sourcef.size(); - - /* size of a MacBinary header is always 128 bytes */ - if (total_size - pad128(datafork_size) - pad128(resourcefork_size) != 128) - return IMGTOOLERR_CORRUPTFILE; - - /* check filename length byte */ - if ((header[1] <= 0x00) || (header[1] > 0x3F)) - return IMGTOOLERR_CORRUPTFILE; - - /* check the CRC */ - if (pick_integer_be(header, 124, 2) != ccitt_crc16(0, header, 124)) - { - /* the CRC does not match; this file is MacBinary I */ - //version = 1; - } - else if (pick_integer_be(header, 102, 4) != 0x6D42494E) - { - /* did not see 'mBIN'; this file is MacBinary II */ - if (header[122] < 0x81) - return IMGTOOLERR_CORRUPTFILE; - if (header[123] < 0x81) - return IMGTOOLERR_CORRUPTFILE; - //version = 2; - } - else - { - /* we did see 'mBIN'; this file is MacBinary III */ - if (header[122] < 0x82) - return IMGTOOLERR_CORRUPTFILE; - if (header[123] < 0x81) - return IMGTOOLERR_CORRUPTFILE; - //version = 3; - } - - type_code = pick_integer_be(header, 65, 4); - creator_code = pick_integer_be(header, 69, 4); - finder_flags = pick_integer_be(header, 73, 1) << 8; - coord_x = pick_integer_be(header, 75, 2); - coord_y = pick_integer_be(header, 77, 2); - finder_folder = pick_integer_be(header, 79, 2); - creation_time = pick_integer_be(header, 91, 4); - lastmodified_time = pick_integer_be(header, 95, 4); - - if (image) - { - /* write out both forks */ - err = write_fork(partition, filename, "", sourcef, sizeof(header), datafork_size, opts); - if (err) - return err; - err = write_fork(partition, filename, "RESOURCE_FORK", sourcef, sizeof(header) + pad128(datafork_size), resourcefork_size, opts); - if (err) - return err; - - /* set up attributes */ - attr_values[0].t = mac_crack_time(creation_time).to_time_t(); - attr_values[1].t = mac_crack_time(lastmodified_time).to_time_t(); - attr_values[2].i = type_code; - attr_values[3].i = creator_code; - attr_values[4].i = finder_flags; - attr_values[5].i = coord_x; - attr_values[6].i = coord_y; - attr_values[7].i = finder_folder; - attr_values[8].i = script_code; - attr_values[9].i = extended_flags; - - err = partition.put_file_attributes(filename, attrs, attr_values); - if (err) - return err; - } - - return IMGTOOLERR_SUCCESS; -} - - -// this was completely broken - it was calling macbinary_writefile() with a nullptr partition -#if 0 -static imgtoolerr_t macbinary_checkstream(imgtool::stream &stream, imgtool_suggestion_viability_t *viability) -{ - imgtoolerr_t err; - - err = macbinary_writefile(NULL, NULL, NULL, stream, NULL); - if (err == IMGTOOLERR_CORRUPTFILE) - { - /* the filter returned corrupt; this is not a valid file */ - *viability = SUGGESTION_END; - err = IMGTOOLERR_SUCCESS; - } - else if (err == IMGTOOLERR_SUCCESS) - { - /* success; lets recommend this filter */ - *viability = SUGGESTION_RECOMMENDED; - } - return err; -} -#endif - - - -void filter_macbinary_getinfo(uint32_t state, union filterinfo *info) -{ - switch(state) - { - case FILTINFO_STR_NAME: info->s = "macbinary"; break; - case FILTINFO_STR_HUMANNAME: info->s = "MacBinary"; break; - case FILTINFO_STR_EXTENSION: info->s = "bin"; break; - case FILTINFO_PTR_READFILE: info->read_file = macbinary_readfile; break; - case FILTINFO_PTR_WRITEFILE: info->write_file = macbinary_writefile; break; - //case FILTINFO_PTR_CHECKSTREAM: info->check_stream = macbinary_checkstream; break; - } -} diff --git a/src/tools/imgtool/modules/macutil.cpp b/src/tools/imgtool/modules/macutil.cpp deleted file mode 100644 index 08c8b84989f..00000000000 --- a/src/tools/imgtool/modules/macutil.cpp +++ /dev/null @@ -1,116 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Raphael Nabet -/**************************************************************************** - - macutil.cpp - - Imgtool Utility code for manipulating certain Apple/Mac data structures - and conventions - -*****************************************************************************/ - -#include "macutil.h" -#include "timeconv.h" - - -typedef util::arbitrary_clock<std::uint32_t, 1904, 1, 1, 0, 0, 0, std::ratio<1, 1> > classic_mac_clock; - -//------------------------------------------------- -// mac_crack_time -//------------------------------------------------- - -imgtool::datetime mac_crack_time(uint32_t t) -{ - classic_mac_clock::duration d(t); - std::chrono::time_point<classic_mac_clock> tp(d); - return imgtool::datetime(imgtool::datetime::datetime_type::LOCAL, tp); -} - - -//------------------------------------------------- -// mac_setup_time -//------------------------------------------------- - -uint32_t mac_setup_time(const imgtool::datetime &t) -{ - auto mac_time_point = classic_mac_clock::from_arbitrary_time_point(t.time_point()); - return mac_time_point.time_since_epoch().count(); -} - - -//------------------------------------------------- -// mac_setup_time -//------------------------------------------------- - -uint32_t mac_setup_time(time_t t) -{ - imgtool::datetime dt(imgtool::datetime::datetime_type::LOCAL, t); - return mac_setup_time(dt); -} - - -//------------------------------------------------- -// mac_time_now -//------------------------------------------------- - -uint32_t mac_time_now(void) -{ - imgtool::datetime dt = imgtool::datetime::now(imgtool::datetime::datetime_type::LOCAL); - return mac_setup_time(dt); -} - - -//------------------------------------------------- -// mac_identify_fork -//------------------------------------------------- - -imgtoolerr_t mac_identify_fork(const char *fork_string, mac_fork_t *fork_num) -{ - if (!strcmp(fork_string, "")) - *fork_num = MAC_FORK_DATA; - else if (!strcmp(fork_string, "RESOURCE_FORK")) - *fork_num = MAC_FORK_RESOURCE; - else - return IMGTOOLERR_FORKNOTFOUND; - return IMGTOOLERR_SUCCESS; -} - - - -void mac_suggest_transfer(mac_filecategory_t file_category, imgtool_transfer_suggestion *suggestions, size_t suggestions_length) -{ - suggestions[0].viability = (file_category == MAC_FILECATEGORY_FORKED) ? SUGGESTION_RECOMMENDED : SUGGESTION_POSSIBLE; - suggestions[0].filter = filter_macbinary_getinfo; - suggestions[0].fork = NULL; - suggestions[0].description = NULL; - - suggestions[1].viability = (file_category == MAC_FILECATEGORY_TEXT) ? SUGGESTION_RECOMMENDED : SUGGESTION_POSSIBLE; - suggestions[1].filter = filter_eoln_getinfo; - suggestions[1].fork = NULL; - suggestions[1].description = NULL; - - suggestions[2].viability = (file_category == MAC_FILECATEGORY_DATA) ? SUGGESTION_RECOMMENDED : SUGGESTION_POSSIBLE; - suggestions[2].filter = NULL; - suggestions[2].fork = ""; - suggestions[2].description = "Raw (data fork)"; - - suggestions[3].viability = SUGGESTION_POSSIBLE; - suggestions[3].filter = NULL; - suggestions[3].fork = "RESOURCE_FORK"; - suggestions[3].description = "Raw (resource fork)"; -} - - - -void pascal_from_c_string(unsigned char *pstring, size_t pstring_len, const char *cstring) -{ - size_t cstring_len, i; - - cstring_len = strlen(cstring); - pstring[0] = std::min(cstring_len, pstring_len - 1); - - for (i = 0; i < pstring[0]; i++) - pstring[1 + i] = cstring[i]; - while(i < pstring_len - 1) - pstring[1 + i++] = '\0'; -} diff --git a/src/tools/imgtool/modules/macutil.h b/src/tools/imgtool/modules/macutil.h deleted file mode 100644 index 0ab3315874b..00000000000 --- a/src/tools/imgtool/modules/macutil.h +++ /dev/null @@ -1,43 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Raphael Nabet -/**************************************************************************** - - macutil.h - - Imgtool Utility code for manipulating certain Apple/Mac data structures - and conventions - -*****************************************************************************/ - -#ifndef MACUTIL_H -#define MACUTIL_H - -#include "imgtool.h" - -enum mac_fork_t -{ - MAC_FORK_DATA, - MAC_FORK_RESOURCE -}; - -enum mac_filecategory_t -{ - MAC_FILECATEGORY_DATA, - MAC_FILECATEGORY_TEXT, - MAC_FILECATEGORY_FORKED -}; - - -/* converting Classic Mac OS time <==> Imgtool time */ -imgtool::datetime mac_crack_time(uint32_t t); -uint32_t mac_setup_time(const imgtool::datetime &t); -uint32_t mac_setup_time(time_t t); -uint32_t mac_time_now(void); - -imgtoolerr_t mac_identify_fork(const char *fork_string, mac_fork_t *fork_num); - -void mac_suggest_transfer(mac_filecategory_t file_category, imgtool_transfer_suggestion *suggestions, size_t suggestions_length); - -void pascal_from_c_string(unsigned char *pstring, size_t pstring_len, const char *cstring); - -#endif /* MACUTIL_H */ diff --git a/src/tools/imgtool/modules/os9.cpp b/src/tools/imgtool/modules/os9.cpp index cc016250c31..97fdcb9e209 100644 --- a/src/tools/imgtool/modules/os9.cpp +++ b/src/tools/imgtool/modules/os9.cpp @@ -8,13 +8,16 @@ ****************************************************************************/ -#include <time.h> - #include "imgtool.h" -#include "formats/imageutl.h" -#include "formats/coco_dsk.h" #include "iflopimg.h" +#include "formats/coco_dsk.h" +#include "multibyte.h" +#include "opresolv.h" + +#include <cstdio> +#include <ctime> + enum creation_policy_t { CREATE_NONE, @@ -44,7 +47,7 @@ struct os9_diskinfo unsigned int octal_track_density : 1; char name[33]; - uint8_t *allocation_bitmap; + uint8_t allocation_bitmap[65536]; }; @@ -96,20 +99,13 @@ static void pick_string(const void *ptr, size_t offset, size_t length, char *des -static void place_string(void *ptr, size_t offset, size_t length, const char *s) +static void place_string(uint8_t *bptr, size_t length, const char *s) { - size_t i; - uint8_t b; - uint8_t *bptr; - - bptr = (uint8_t *) ptr; - bptr += offset; - bptr[0] = 0x80; - for (i = 0; s[i] && (i < length); i++) + for (size_t i = 0; s[i] && (i < length); i++) { - b = ((uint8_t) s[i]) & 0x7F; + uint8_t b = ((uint8_t) s[i]) & 0x7F; if (s[i+1] == '\0') b |= 0x80; bptr[i] = b; @@ -228,7 +224,7 @@ static int os9_interpret_dirent(void *entry, char **filename, uint32_t *lsn, int entry_b[i] &= 0x7F; entry_b[i+1] = '\0'; - *lsn = pick_integer_be(entry, 29, 3); + *lsn = get_u24be((uint8_t *) &entry_b[29]); if (strcmp(entry_b, ".") && strcmp(entry_b, "..")) *filename = entry_b; return *filename != NULL; @@ -257,10 +253,10 @@ static imgtoolerr_t os9_decode_file_header(imgtool::image &image, return err; info->lsn = lsn; - attributes = pick_integer_be(header, 0, 1); - info->owner_id = pick_integer_be(header, 1, 2); - info->link_count = pick_integer_be(header, 8, 1); - info->file_size = pick_integer_be(header, 9, 4); + attributes = header[0]; + info->owner_id = get_u16be(&header[1]); + info->link_count = header[8]; + info->file_size = get_u32be(&header[9]); info->directory = (attributes & 0x80) ? 1 : 0; info->non_sharable = (attributes & 0x40) ? 1 : 0; info->public_execute = (attributes & 0x20) ? 1 : 0; @@ -275,11 +271,11 @@ static imgtoolerr_t os9_decode_file_header(imgtool::image &image, /* read all sector map entries */ max_entries = (disk_info->sector_size - 16) / 5; - max_entries = (std::min<std::size_t>)(max_entries, ARRAY_LENGTH(info->sector_map) - 1); + max_entries = (std::min<std::size_t>)(max_entries, std::size(info->sector_map) - 1); for (i = 0; i < max_entries; i++) { - lsn = pick_integer_be(header, 16 + (i * 5) + 0, 3); - count = pick_integer_be(header, 16 + (i * 5) + 3, 2); + lsn = get_u24be(&header[16 + (i * 5) + 0]); + count = get_u16be(&header[16 + (i * 5) + 3]); if (count <= 0) break; @@ -393,7 +389,7 @@ static imgtoolerr_t os9_set_file_size(imgtool::image &image, /* first find out the size of our sector map */ sector_map_length = 0; lsn = 0; - while((lsn < current_lsn_count) && (sector_map_length < ARRAY_LENGTH(file_info->sector_map))) + while((lsn < current_lsn_count) && (sector_map_length < std::size(file_info->sector_map))) { if (file_info->sector_map[sector_map_length].count == 0) return os9_corrupt_file_error(file_info); @@ -434,7 +430,7 @@ static imgtoolerr_t os9_set_file_size(imgtool::image &image, { file_info->sector_map[sector_map_length - 1].count++; } - else if (sector_map_length >= ARRAY_LENGTH(file_info->sector_map)) + else if (sector_map_length >= std::size(file_info->sector_map)) { return IMGTOOLERR_NOSPACE; } @@ -456,15 +452,15 @@ static imgtoolerr_t os9_set_file_size(imgtool::image &image, return err; file_info->file_size = new_size; - place_integer_be(header, 9, 4, file_info->file_size); + put_u32be(&header[9], file_info->file_size); /* do we have to write the sector map? */ if (sector_map_length >= 0) { - for (i = 0; i < (std::min<std::size_t>)(sector_map_length + 1, ARRAY_LENGTH(file_info->sector_map)); i++) + for (i = 0; i < (std::min<std::size_t>)(sector_map_length + 1, std::size(file_info->sector_map)); i++) { - place_integer_be(header, 16 + (i * 5) + 0, 3, file_info->sector_map[i].lsn); - place_integer_be(header, 16 + (i * 5) + 3, 2, file_info->sector_map[i].count); + put_u24be(&header[16 + (i * 5) + 0], file_info->sector_map[i].lsn); + put_u16be(&header[16 + (i * 5) + 3], file_info->sector_map[i].count); } } @@ -567,7 +563,7 @@ static imgtoolerr_t os9_lookup_path(imgtool::image &img, const char *path, /* write the file */ memset(block, 0, sizeof(block)); - place_integer_be(block, 0, 1, 0x1B | ((create == CREATE_DIR) ? 0x80 : 0x00)); + block[0] = 0x1B | ((create == CREATE_DIR) ? 0x80 : 0x00); err = os9_write_lsn(img, allocated_lsn, 0, block, sizeof(block)); if (err) goto done; @@ -585,8 +581,8 @@ static imgtoolerr_t os9_lookup_path(imgtool::image &img, const char *path, /* now prepare the directory entry */ memset(entry, 0, sizeof(entry)); - place_string(entry, 0, 28, path); - place_integer_be(entry, 29, 3, allocated_lsn); + place_string(&entry[0], 28, path); + put_u24be(&entry[29], allocated_lsn); /* now write the directory entry */ entry_index = dir_size; @@ -638,20 +634,19 @@ static imgtoolerr_t os9_diskimage_open(imgtool::image &image, imgtool::stream::p if (ferr) return imgtool_floppy_error(ferr); - info->total_sectors = pick_integer_be(header, 0, 3); - track_size_in_sectors = pick_integer_be(header, 3, 1); - info->allocation_bitmap_bytes = pick_integer_be(header, 4, 2); - info->cluster_size = pick_integer_be(header, 6, 2); - info->root_dir_lsn = pick_integer_be(header, 8, 3); - info->owner_id = pick_integer_be(header, 11, 2); -// attributes = - pick_integer_be(header, 13, 1); - info->disk_id = pick_integer_be(header, 14, 2); - info->format_flags = pick_integer_be(header, 16, 1); - info->sectors_per_track = pick_integer_be(header, 17, 2); - info->bootstrap_lsn = pick_integer_be(header, 21, 3); - info->bootstrap_size = pick_integer_be(header, 24, 2); - info->sector_size = pick_integer_be(header, 104, 2); + info->total_sectors = get_u24be(&header[ 0]); + track_size_in_sectors = header[ 3]; + info->allocation_bitmap_bytes = get_u16be(&header[ 4]); + info->cluster_size = get_u16be(&header[ 6]); + info->root_dir_lsn = get_u24be(&header[ 8]); + info->owner_id = get_u16be(&header[ 11]); +// attributes = header[ 13]; + info->disk_id = get_u16be(&header[ 14]); + info->format_flags = header[ 16]; + info->sectors_per_track = get_u16be(&header[ 17]); + info->bootstrap_lsn = get_u24be(&header[ 21]); + info->bootstrap_size = get_u16be(&header[ 24]); + info->sector_size = get_u16be(&header[104]); info->sides = (info->format_flags & 0x01) ? 2 : 1; info->double_density = (info->format_flags & 0x02) ? 1 : 0; @@ -670,10 +665,7 @@ static imgtoolerr_t os9_diskimage_open(imgtool::image &image, imgtool::stream::p return IMGTOOLERR_CORRUPTIMAGE; /* is the allocation bitmap too big? */ - info->allocation_bitmap = (uint8_t*)image.malloc(info->allocation_bitmap_bytes); - if (!info->allocation_bitmap) - return IMGTOOLERR_OUTOFMEMORY; - memset(info->allocation_bitmap, 0, info->allocation_bitmap_bytes); + memset(&info->allocation_bitmap[0], 0, info->allocation_bitmap_bytes); /* sectors per track and track size don't jive? */ if (info->sectors_per_track != track_size_in_sectors) @@ -747,30 +739,30 @@ static imgtoolerr_t os9_diskimage_create(imgtool::image &img, imgtool::stream::p format_flags = ((heads > 1) ? 0x01 : 0x00) | ((tracks > 40) ? 0x02 : 0x00); memset(&header[0], 0, sector_bytes); - place_integer_be(&header[0], 0, 3, heads * tracks * sectors); - place_integer_be(&header[0], 3, 1, sectors); - place_integer_be(&header[0], 4, 2, (allocation_bitmap_bits + 7) / 8); - place_integer_be(&header[0], 6, 2, cluster_size); - place_integer_be(&header[0], 8, 3, 1 + allocation_bitmap_lsns); - place_integer_be(&header[0], 11, 2, owner_id); - place_integer_be(&header[0], 13, 1, attributes); - place_integer_be(&header[0], 14, 2, disk_id); - place_integer_be(&header[0], 16, 1, format_flags); - place_integer_be(&header[0], 17, 2, sectors); - place_string(&header[0], 31, 32, title); - place_integer_be(&header[0], 103, 2, sector_bytes / 256); + put_u24be(&header[ 0], heads * tracks * sectors); + header[ 3] = sectors; + put_u16be(&header[ 4], (allocation_bitmap_bits + 7) / 8); + put_u16be(&header[ 6], cluster_size); + put_u24be(&header[ 8], 1 + allocation_bitmap_lsns); + put_u16be(&header[ 11], owner_id); + header[ 13] = attributes; + put_u16be(&header[ 14], disk_id); + header[ 16] = format_flags; + put_u16be(&header[ 17], sectors); + place_string(&header[ 31], 32, title); + put_u16be(&header[103], sector_bytes / 256); /* path descriptor options */ - place_integer_be(&header[0], 0x3f+0x00, 1, 1); /* device class */ - place_integer_be(&header[0], 0x3f+0x01, 1, 1); /* drive number */ - place_integer_be(&header[0], 0x3f+0x03, 1, 0x20); /* device type */ - place_integer_be(&header[0], 0x3f+0x04, 1, 1); /* density capability */ - place_integer_be(&header[0], 0x3f+0x05, 2, tracks); /* number of tracks */ - place_integer_be(&header[0], 0x3f+0x07, 1, heads); /* number of sides */ - place_integer_be(&header[0], 0x3f+0x09, 2, sectors); /* sectors per track */ - place_integer_be(&header[0], 0x3f+0x0b, 2, sectors); /* sectors on track zero */ - place_integer_be(&header[0], 0x3f+0x0d, 1, 3); /* sector interleave factor */ - place_integer_be(&header[0], 0x3f+0x0e, 1, 8); /* default sectors per allocation */ + header[0x3f+0x00] = 1; /* device class */ + header[0x3f+0x01] = 1; /* drive number */ + header[0x3f+0x03] = 0x20; /* device type */ + header[0x3f+0x04] = 1; /* density capability */ + put_u16be(&header[0x3f+0x05], tracks); /* number of tracks */ + header[0x3f+0x07] = heads; /* number of sides */ + put_u16be(&header[0x3f+0x09], sectors); /* sectors per track */ + put_u16be(&header[0x3f+0x0b], sectors); /* sectors on track zero */ + header[0x3f+0x0d] = 3; /* sector interleave factor */ + header[0x3f+0x0e] = 8; /* default sectors per allocation */ err = (imgtoolerr_t)floppy_write_sector(imgtool_floppy(img), 0, 0, first_sector_id, 0, &header[0], sector_bytes, 0); /* TODO: pass ddam argument from imgtool */ if (err) @@ -824,8 +816,8 @@ static imgtoolerr_t os9_diskimage_create(imgtool::image &img, imgtool::stream::p header[0x0D] = (uint8_t) (ltime->tm_year % 100); header[0x0E] = (uint8_t) ltime->tm_mon; header[0x0F] = (uint8_t) ltime->tm_mday; - place_integer_be(&header[0], 0x10, 3, 1 + allocation_bitmap_lsns + 1); - place_integer_be(&header[0], 0x13, 2, 8); + put_u24be(&header[0x10], 1 + allocation_bitmap_lsns + 1); + put_u16be(&header[0x13], 8); err = (imgtoolerr_t)floppy_write_sector(imgtool_floppy(img), 0, 0, first_sector_id + 1 + allocation_bitmap_lsns, 0, &header[0], sector_bytes, 0); /* TODO: pass ddam argument from imgtool */ if (err) @@ -929,7 +921,7 @@ static imgtoolerr_t os9_diskimage_nextenum(imgtool::directory &enumeration, imgt } /* if the filename is ".", the file should point to the current directory */ - if (!strcmp(filename, ".") && (pick_integer_be(dir_entry, 29, 3) != os9enum->dir_info.lsn)) + if (!strcmp(filename, ".") && (get_u24be(&dir_entry[29]) != os9enum->dir_info.lsn)) { imgtool_warn("Directory \".\" does not point back to same directory"); } @@ -946,14 +938,14 @@ static imgtoolerr_t os9_diskimage_nextenum(imgtool::directory &enumeration, imgt while(!filename[0] || !strcmp(filename, ".") || !strcmp(filename, "..")); /* read file attributes */ - lsn = pick_integer_be(dir_entry, 29, 3); + lsn = get_u24be(&dir_entry[29]); err = os9_decode_file_header(enumeration.image(), lsn, &file_info); if (err) return err; /* fill out imgtool_dirent structure */ - snprintf(ent.filename, ARRAY_LENGTH(ent.filename), "%s", filename); - snprintf(ent.attr, ARRAY_LENGTH(ent.attr), "%c%c%c%c%c%c%c%c", + snprintf(ent.filename, std::size(ent.filename), "%s", filename); + snprintf(ent.attr, std::size(ent.attr), "%c%c%c%c%c%c%c%c", file_info.directory ? 'd' : '-', file_info.non_sharable ? 's' : '-', file_info.public_execute ? 'x' : '-', @@ -1143,7 +1135,7 @@ static imgtoolerr_t os9_diskimage_delete(imgtool::partition &partition, const ch if (err) return err; - for (i = 0; (i < ARRAY_LENGTH(file_info.sector_map)) && file_info.sector_map[i].count; i++) + for (i = 0; (i < std::size(file_info.sector_map)) && file_info.sector_map[i].count; i++) { lsn = file_info.sector_map[i].lsn; for (j = 0; j < file_info.sector_map[i].count; j++) @@ -1185,10 +1177,10 @@ static imgtoolerr_t os9_diskimage_createdir(imgtool::partition &partition, const /* create intial directories */ memset(dir_data, 0, sizeof(dir_data)); - place_string(dir_data, 0, 32, ".."); - place_integer_be(dir_data, 29, 3, parent_lsn); - place_string(dir_data, 32, 32, "."); - place_integer_be(dir_data, 61, 3, file_info.lsn); + place_string(&dir_data[ 0], 32, ".."); + put_u24be(&dir_data[29], parent_lsn); + place_string(&dir_data[32], 32, "."); + put_u24be(&dir_data[61], file_info.lsn); err = os9_write_lsn(image, file_info.sector_map[0].lsn, 0, dir_data, sizeof(dir_data)); if (err) diff --git a/src/tools/imgtool/modules/pc_flop.cpp b/src/tools/imgtool/modules/pc_flop.cpp index 211b7f7b938..6a242d16abf 100644 --- a/src/tools/imgtool/modules/pc_flop.cpp +++ b/src/tools/imgtool/modules/pc_flop.cpp @@ -9,11 +9,14 @@ ****************************************************************************/ #include "imgtool.h" -#include "formats/imageutl.h" -#include "formats/pc_dsk.h" #include "fat.h" #include "iflopimg.h" +#include "formats/pc_dsk_legacy.h" + +#include "multibyte.h" +#include "opresolv.h" + #define FAT_SECLEN 512 @@ -31,10 +34,10 @@ static imgtoolerr_t fat_image_create(imgtool::image &image, imgtool::stream::ptr /* set up just enough of a boot sector to specify geometry */ memset(buffer, 0, sizeof(buffer)); - place_integer_le(buffer, 24, 2, sectors); - place_integer_le(buffer, 26, 2, heads); - place_integer_le(buffer, 19, 2, (uint16_t) (((uint64_t) tracks * heads * sectors) >> 0)); - place_integer_le(buffer, 32, 4, (uint16_t) (((uint64_t) tracks * heads * sectors) >> 16)); + put_u16le(&buffer[24], sectors); + put_u16le(&buffer[26], heads); + put_u16le(&buffer[19], uint16_t((uint64_t(tracks) * heads * sectors) >> 0)); + put_u32le(&buffer[32], uint16_t((uint64_t(tracks) * heads * sectors) >> 16)); err = image.write_block(0, buffer); if (err) goto done; @@ -44,7 +47,7 @@ static imgtoolerr_t fat_image_create(imgtool::image &image, imgtool::stream::ptr imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_CREATE_PARTITION); /* actually create the partition */ - err = fat_partition_create(image, 0, ((uint64_t) tracks) * heads * sectors); + err = fat_partition_create(image, 0, uint64_t(tracks) * heads * sectors); if (err) goto done; @@ -64,11 +67,11 @@ static imgtoolerr_t fat_image_get_geometry(imgtool::image &image, uint32_t *trac if (err) return err; - total_sectors = pick_integer_le(buffer, 19, 2) - | (pick_integer_le(buffer, 32, 4) << 16); + total_sectors = get_u16le(&buffer[19]) + | uint64_t(get_u32le(&buffer[32]) << 16); - *sectors = pick_integer_le(buffer, 24, 2); - *heads = pick_integer_le(buffer, 26, 2); + *sectors = get_u16le(&buffer[24]); + *heads = get_u16le(&buffer[26]); *tracks = total_sectors / *heads / *sectors; return IMGTOOLERR_SUCCESS; } diff --git a/src/tools/imgtool/modules/pc_hard.cpp b/src/tools/imgtool/modules/pc_hard.cpp index c04ad33cce6..353a6b5dac5 100644 --- a/src/tools/imgtool/modules/pc_hard.cpp +++ b/src/tools/imgtool/modules/pc_hard.cpp @@ -50,9 +50,11 @@ ****************************************************************************/ #include "imgtool.h" -#include "formats/imageutl.h" #include "imghd.h" +#include "multibyte.h" +#include "opresolv.h" + #define FAT_SECLEN 512 OPTION_GUIDE_START( pc_chd_create_optionguide ) @@ -103,15 +105,12 @@ static pc_chd_image_info *pc_chd_get_image_info(imgtool::image &image) static void pc_chd_locate_block(imgtool::image &image, uint64_t block, uint32_t *cylinder, uint32_t *head, uint32_t *sector) { - pc_chd_image_info *info; - const hard_disk_info *hd_info; - - info = pc_chd_get_image_info(image); - hd_info = imghd_get_header(&info->hard_disk); + pc_chd_image_info *info = pc_chd_get_image_info(image); + const auto &hd_info = imghd_get_header(&info->hard_disk); - *sector = block % hd_info->sectors; - *head = (block / hd_info->sectors) % hd_info->heads; - *cylinder = block / hd_info->sectors / hd_info->heads; + *sector = block % hd_info.sectors; + *head = (block / hd_info.sectors) % hd_info.heads; + *cylinder = block / hd_info.sectors / hd_info.heads; } @@ -168,16 +167,16 @@ static imgtoolerr_t pc_chd_partition_create(imgtool::image &image, int partition /* fill out the partition entry */ partition_entry = &header_block[446 + (partition_index * 16)]; - place_integer_le(partition_entry, 0, 1, 0x80); - place_integer_le(partition_entry, 1, 1, first_head); - place_integer_le(partition_entry, 2, 1, ((first_sector & 0x3F) | (first_cylinder >> 8 << 2))); - place_integer_le(partition_entry, 3, 1, first_cylinder); - place_integer_le(partition_entry, 4, 1, partition_type); - place_integer_le(partition_entry, 5, 1, last_head); - place_integer_le(partition_entry, 6, 1, ((last_sector & 0x3F) | (last_cylinder >> 8 << 2))); - place_integer_le(partition_entry, 7, 1, last_cylinder); - place_integer_le(partition_entry, 8, 4, first_block); - place_integer_le(partition_entry, 12, 4, block_count); + partition_entry[0] = 0x80; + partition_entry[1] = first_head; + partition_entry[2] = ((first_sector & 0x3F) | (first_cylinder >> 8 << 2)); + partition_entry[3] = first_cylinder; + partition_entry[4] = partition_type; + partition_entry[5] = last_head; + partition_entry[6] = ((last_sector & 0x3F) | (last_cylinder >> 8 << 2)); + partition_entry[7] = last_cylinder; + put_u32le(&partition_entry[ 8], first_block); + put_u32le(&partition_entry[12], block_count); /* write the partition header */ err = image.write_block(0, header_block); @@ -193,7 +192,6 @@ done: static imgtoolerr_t pc_chd_read_partition_header(imgtool::image &image) { imgtoolerr_t err; - int i; const uint8_t *partition_info; pc_chd_image_info *info; uint8_t buffer[FAT_SECLEN]; @@ -209,7 +207,7 @@ static imgtoolerr_t pc_chd_read_partition_header(imgtool::image &image) if ((buffer[510] != 0x55) || (buffer[511] != 0xAA)) return IMGTOOLERR_CORRUPTIMAGE; - for (i = 0; i < ARRAY_LENGTH(info->partitions); i++) + for (int i = 0; i < std::size(info->partitions); i++) { partition_info = &buffer[446 + i * 16]; @@ -221,8 +219,8 @@ static imgtoolerr_t pc_chd_read_partition_header(imgtool::image &image) info->partitions[i].ending_track = ((partition_info[6] << 2) & 0xFF00) | partition_info[7]; info->partitions[i].ending_sector = partition_info[6] & 0x3F; - info->partitions[i].sector_index = pick_integer_le(partition_info, 8, 4); - info->partitions[i].total_sectors = pick_integer_le(partition_info, 12, 4); + info->partitions[i].sector_index = get_u32le(&partition_info[ 8]); + info->partitions[i].total_sectors = get_u32le(&partition_info[12]); if (info->partitions[i].starting_track > info->partitions[i].ending_track) return IMGTOOLERR_CORRUPTIMAGE; @@ -310,15 +308,12 @@ static void pc_chd_image_close(imgtool::image &image) static imgtoolerr_t pc_chd_image_get_geometry(imgtool::image &image, uint32_t *tracks, uint32_t *heads, uint32_t *sectors) { - pc_chd_image_info *info; - const hard_disk_info *hd_info; - - info = pc_chd_get_image_info(image); - hd_info = imghd_get_header(&info->hard_disk); + pc_chd_image_info *info = pc_chd_get_image_info(image); + const auto &hd_info = imghd_get_header(&info->hard_disk); - *tracks = hd_info->cylinders; - *heads = hd_info->heads; - *sectors = hd_info->sectors; + *tracks = hd_info.cylinders; + *heads = hd_info.heads; + *sectors = hd_info.sectors; return IMGTOOLERR_SUCCESS; } @@ -327,13 +322,11 @@ static imgtoolerr_t pc_chd_image_get_geometry(imgtool::image &image, uint32_t *t static uint32_t pc_chd_calc_lbasector(pc_chd_image_info &info, uint32_t track, uint32_t head, uint32_t sector) { uint32_t lbasector; - const hard_disk_info *hd_info; - - hd_info = imghd_get_header(&info.hard_disk); + const auto &hd_info = imghd_get_header(&info.hard_disk); lbasector = track; - lbasector *= hd_info->heads; + lbasector *= hd_info.heads; lbasector += head; - lbasector *= hd_info->sectors; + lbasector *= hd_info.sectors; lbasector += sector; return lbasector; } @@ -345,7 +338,7 @@ static imgtoolerr_t pc_chd_image_readsector(imgtool::image &image, uint32_t trac pc_chd_image_info *info = pc_chd_get_image_info(image); // get the sector size and resize the buffer - uint32_t sector_size = imghd_get_header(&info->hard_disk)->sectorbytes; + uint32_t sector_size = imghd_get_header(&info->hard_disk).sectorbytes; try { buffer.resize(sector_size); } catch (std::bad_alloc const &) { return IMGTOOLERR_OUTOFMEMORY; } diff --git a/src/tools/imgtool/modules/prodos.cpp b/src/tools/imgtool/modules/prodos.cpp deleted file mode 100644 index 6db41ae529b..00000000000 --- a/src/tools/imgtool/modules/prodos.cpp +++ /dev/null @@ -1,2267 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Raphael Nabet -/**************************************************************************** - - prodos.cpp - - Apple II ProDOS disk images - -***************************************************************************** - - Notes: - - ProDOS disks are split into 512 byte blocks. - - ProDOS directory structure: - - Offset Length Description - ------ ------ ----------- - 0 2 ??? - 2 2 Next block (0 if end) - 4 39 Directory Entry - 43 39 Directory Entry - ... - 472 39 Directory Entry - 511 1 ??? - - - ProDOS directory entry structure: - - Offset Length Description - ------ ------ ----------- - 0 1 Storage type (bits 7-4) - 10 - Seedling File (1 block) - 20 - Sapling File (2-256 blocks) - 30 - Tree File (257-32768 blocks) - 40 - Pascal Areas on ProFile HDs (???) - 50 - GS/OS Extended File (data and rsrc fork) - E0 - Subdirectory Header - F0 - Volume Header - 1 15 File name (NUL padded) - 16 1 File type - 17 2 Key pointer - 19 2 Blocks used - 21 3 File size - 24 4 Creation date - 28 1 ProDOS version that created the file - 29 1 Minimum ProDOS version needed to read the file - 30 1 Access byte - 31 2 Auxilary file type - 33 4 Last modified date - 37 2 Header pointer - - - In "seedling files", the key pointer points to a single block that is the - whole file. In "sapling files", the key pointer points to an index block - that contains 256 2-byte index pointers that point to the actual blocks of - the files. These 2-byte values are not contiguous; the low order byte is - in the first half of the block, and the high order byte is in the second - half of the block. In "tree files", the key pointer points to an index - block of index blocks. - - ProDOS dates are 32-bit little endian values - - bits 0- 4 Day - bits 5- 8 Month (0-11) - bits 9-15 Year (0-49 is 2000-2049, 50-99 is 1950-1999) - bits 16-21 Minute - bits 24-28 Hour - - - ProDOS directory and volume headers have this information: - - Offset Length Description - ------ ------ ----------- - 31 1 Length of the entry; generally is 39 - 32 1 Number of entries per block; generally is 13 - 33 2 Active entry count in directory - 35 2 Volume bitmap block number - 37 2 Total blocks on volume - - GS/OS Extended Files (storage type $5) point to an extended key block that - contains information about the two forks. The first half of the extended - key block contains info about the data form, and the second half the - resource fork. Both sides have the following format: - - Offset Length Description - ------ ------ ----------- - 0 1 Storage type (bits 3-0, unlike the directory entry) - 1 2 Key pointer - 3 2 Blocks used - 5 3 File size - 8 1 Size of secondary info #1 (must be 18 to be valid) - 9 1 Secondary info #1 type (1=FInfo 2=xFInfo) - 10 16 FInfo or xFInfo - 26 1 Size of secondary info #2 (must be 18 to be valid) - 27 1 Secondary info #2 type (1=FInfo 2=xFInfo) - 28 16 FInfo or xFInfo - - FInfo format: - - Offset Length Description - ------ ------ ----------- - 0 4 File type - 4 4 File creator - 8 2 Finder flags - 10 2 X Coordinate - 12 2 Y Coordinate - 14 2 Finder folder - - xFInfo format: - - Offset Length Description - ------ ------ ----------- - 0 2 Icon ID - 2 6 Reserved - 8 1 Script Code - 9 1 Extended flags - 10 2 Comment ID - 12 4 Put Away Directory - - - For more info, consult ProDOS technical note #25 - (http://web.pdx.edu/~heiss/technotes/pdos/tn.pdos.25.html) - -*****************************************************************************/ - -#include "imgtool.h" -#include "formats/imageutl.h" -#include "formats/ap2_dsk.h" -#include "formats/ap_dsk35.h" -#include "iflopimg.h" -#include "macutil.h" - -#define ROOTDIR_BLOCK 2 -#define BLOCK_SIZE 512 - -struct prodos_diskinfo -{ - imgtoolerr_t (*load_block)(imgtool::image &image, int block, void *buffer); - imgtoolerr_t (*save_block)(imgtool::image &image, int block, const void *buffer); - uint8_t dirent_size; - uint8_t dirents_per_block; - uint16_t volume_bitmap_block; - uint16_t total_blocks; -}; - -struct prodos_direnum -{ - uint32_t block; - uint32_t index; - uint8_t block_data[BLOCK_SIZE]; -}; - -struct prodos_dirent -{ - char filename[16]; - uint8_t storage_type; - uint16_t extkey_pointer; - uint16_t key_pointer[2]; - uint32_t filesize[2]; - int depth[2]; - uint32_t lastmodified_time; - uint32_t creation_time; - - /* FInfo */ - uint32_t file_type; - uint32_t file_creator; - uint16_t finder_flags; - uint16_t coord_x; - uint16_t coord_y; - uint16_t finder_folder; - - /* xFInfo */ - uint16_t icon_id; - uint8_t script_code; - uint8_t extended_flags; - uint16_t comment_id; - uint32_t putaway_directory; -}; - -enum creation_policy_t -{ - CREATE_NONE, - CREATE_FILE, - CREATE_DIR -}; - - - -static imgtool::datetime prodos_crack_time(uint32_t prodos_time) -{ - util::arbitrary_datetime dt; - dt.second = 0; - dt.minute = ((prodos_time >> 16) & 0x3F); - dt.hour = ((prodos_time >> 24) & 0x1F); - dt.day_of_month = ((prodos_time >> 0) & 0x1F); - dt.month = ((prodos_time >> 5) & 0x0F) + 1; - dt.year = ((prodos_time >> 9) & 0x7F) + 1900; - if (dt.year <= 1949) - dt.year += 100; - - return imgtool::datetime(imgtool::datetime::datetime_type::LOCAL, dt); -} - - - -static uint32_t prodos_setup_time(time_t ansi_time) -{ - struct tm t; - uint32_t result = 0; - - t = *localtime(&ansi_time); - if ((t.tm_year >= 100) && (t.tm_year <= 149)) - t.tm_year -= 100; - - result |= (((uint32_t) t.tm_min) & 0x003F) << 16; - result |= (((uint32_t) t.tm_hour) & 0x001F) << 24; - result |= (((uint32_t) t.tm_mday) & 0x001F) << 0; - result |= (((uint32_t) t.tm_mon) & 0x000F) << 5; - result |= (((uint32_t) t.tm_year) & 0x007F) << 9; - return result; -} - - - -static uint32_t prodos_time_now(void) -{ - time_t now; - time(&now); - return prodos_setup_time(now); -} - - - -static int is_file_storagetype(uint8_t storage_type) -{ - return ((storage_type >= 0x10) && (storage_type <= 0x3F)) - || ((storage_type >= 0x50) && (storage_type <= 0x5F)); -} - - - -static int is_normalfile_storagetype(uint8_t storage_type) -{ - return ((storage_type >= 0x10) && (storage_type <= 0x3F)); -} - - - -static int is_extendedfile_storagetype(uint8_t storage_type) -{ - return ((storage_type >= 0x50) && (storage_type <= 0x5F)); -} - - - -static int is_dir_storagetype(uint8_t storage_type) -{ - return (storage_type >= 0xE0) && (storage_type <= 0xEF); -} - - - -static prodos_diskinfo *get_prodos_info(imgtool::image &image) -{ - prodos_diskinfo *info; - info = (prodos_diskinfo *) imgtool_floppy_extrabytes(image); - return info; -} - - - -/* ----------------------------------------------------------------------- */ - -static void prodos_find_block_525(imgtool::image &image, int block, - uint32_t *track, uint32_t *head, uint32_t *sector1, uint32_t *sector2) -{ - static const uint8_t skewing[] = - { - 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, - 0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F - }; - - block *= 2; - - *track = block / APPLE2_SECTOR_COUNT; - *head = 0; - *sector1 = skewing[block % APPLE2_SECTOR_COUNT + 0]; - *sector2 = skewing[block % APPLE2_SECTOR_COUNT + 1]; -} - - - -static imgtoolerr_t prodos_load_block_525(imgtool::image &image, - int block, void *buffer) -{ - floperr_t ferr; - uint32_t track, head, sector1, sector2; - - prodos_find_block_525(image, block, &track, &head, §or1, §or2); - - /* read first sector */ - ferr = floppy_read_sector(imgtool_floppy(image), head, track, - sector1, 0, ((uint8_t *) buffer) + 0, 256); - if (ferr) - return imgtool_floppy_error(ferr); - - /* read second sector */ - ferr = floppy_read_sector(imgtool_floppy(image), head, track, - sector2, 0, ((uint8_t *) buffer) + 256, 256); - if (ferr) - return imgtool_floppy_error(ferr); - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_save_block_525(imgtool::image &image, - int block, const void *buffer) -{ - floperr_t ferr; - uint32_t track, head, sector1, sector2; - - prodos_find_block_525(image, block, &track, &head, §or1, §or2); - - /* read first sector */ - ferr = floppy_write_sector(imgtool_floppy(image), head, track, - sector1, 0, ((const uint8_t *) buffer) + 0, 256, 0); /* TODO: pass ddam argument from imgtool */ - if (ferr) - return imgtool_floppy_error(ferr); - - /* read second sector */ - ferr = floppy_write_sector(imgtool_floppy(image), head, track, - sector2, 0, ((const uint8_t *) buffer) + 256, 256, 0); /* TODO: pass ddam argument from imgtool */ - if (ferr) - return imgtool_floppy_error(ferr); - - return IMGTOOLERR_SUCCESS; -} - - - -static void prodos_setprocs_525(imgtool::image &image) -{ - prodos_diskinfo *info; - info = get_prodos_info(image); - info->load_block = prodos_load_block_525; - info->save_block = prodos_save_block_525; -} - - - -/* ----------------------------------------------------------------------- */ - -static imgtoolerr_t prodos_find_block_35(imgtool::image &image, int block, - uint32_t *track, uint32_t *head, uint32_t *sector) -{ - int sides = 2; - - *track = 0; - while(block >= (apple35_sectors_per_track(imgtool_floppy(image), *track) * sides)) - { - block -= (apple35_sectors_per_track(imgtool_floppy(image), (*track)++) * sides); - if (*track >= 80) - return IMGTOOLERR_SEEKERROR; - } - - *head = block / apple35_sectors_per_track(imgtool_floppy(image), *track); - *sector = block % apple35_sectors_per_track(imgtool_floppy(image), *track); - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_load_block_35(imgtool::image &image, - int block, void *buffer) -{ - imgtoolerr_t err; - floperr_t ferr; - uint32_t track, head, sector; - - err = prodos_find_block_35(image, block, &track, &head, §or); - if (err) - return err; - - ferr = floppy_read_sector(imgtool_floppy(image), head, track, sector, 0, buffer, 512); - if (ferr) - return imgtool_floppy_error(ferr); - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_save_block_35(imgtool::image &image, - int block, const void *buffer) -{ - imgtoolerr_t err; - floperr_t ferr; - uint32_t track, head, sector; - - err = prodos_find_block_35(image, block, &track, &head, §or); - if (err) - return err; - - ferr = floppy_write_sector(imgtool_floppy(image), head, track, sector, 0, buffer, 512, 0); /* TODO: pass ddam argument from imgtool */ - if (ferr) - return imgtool_floppy_error(ferr); - - return IMGTOOLERR_SUCCESS; -} - - - -static void prodos_setprocs_35(imgtool::image &image) -{ - prodos_diskinfo *info; - info = get_prodos_info(image); - info->load_block = prodos_load_block_35; - info->save_block = prodos_save_block_35; -} - - - -/* ----------------------------------------------------------------------- */ - -static imgtoolerr_t prodos_load_block(imgtool::image &image, - int block, void *buffer) -{ - prodos_diskinfo *diskinfo; - diskinfo = get_prodos_info(image); - return diskinfo->load_block(image, block, buffer); -} - - - -static imgtoolerr_t prodos_save_block(imgtool::image &image, - int block, const void *buffer) -{ - prodos_diskinfo *diskinfo; - diskinfo = get_prodos_info(image); - return diskinfo->save_block(image, block, buffer); -} - - - -static imgtoolerr_t prodos_clear_block(imgtool::image &image, int block) -{ - uint8_t buffer[BLOCK_SIZE]; - memset(buffer, 0, sizeof(buffer)); - return prodos_save_block(image, block, buffer); -} - - - -/* ----------------------------------------------------------------------- */ - -static imgtoolerr_t prodos_diskimage_open(imgtool::image &image) -{ - imgtoolerr_t err; - uint8_t buffer[BLOCK_SIZE]; - prodos_diskinfo *di; - const uint8_t *ent; - - di = get_prodos_info(image); - - /* specify defaults */ - di->dirent_size = 39; - di->dirents_per_block = 13; - - /* load the first block, hoping that the volume header is first */ - err = prodos_load_block(image, ROOTDIR_BLOCK, buffer); - if (err) - return err; - - ent = &buffer[4]; - - /* did we find the volume header? */ - if ((ent[0] & 0xF0) == 0xF0) - { - di->dirent_size = pick_integer_le(ent, 31, 1); - di->dirents_per_block = pick_integer_le(ent, 32, 1); - di->volume_bitmap_block = pick_integer_le(ent, 35, 2); - di->total_blocks = pick_integer_le(ent, 37, 2); - } - - /* sanity check these values */ - if (di->dirent_size < 39) - return IMGTOOLERR_CORRUPTIMAGE; - if (di->dirents_per_block * di->dirent_size >= BLOCK_SIZE) - return IMGTOOLERR_CORRUPTIMAGE; - if (di->volume_bitmap_block >= di->total_blocks) - return IMGTOOLERR_CORRUPTIMAGE; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_diskimage_open_525(imgtool::image &image, imgtool::stream::ptr &&dummy) -{ - prodos_setprocs_525(image); - return prodos_diskimage_open(image); -} - - - -static imgtoolerr_t prodos_diskimage_open_35(imgtool::image &image, imgtool::stream::ptr &&dummy) -{ - prodos_setprocs_35(image); - return prodos_diskimage_open(image); -} - - - -/* ----------------------------------------------------------------------- */ - -static imgtoolerr_t prodos_load_volume_bitmap(imgtool::image &image, uint8_t **bitmap) -{ - imgtoolerr_t err; - prodos_diskinfo *di; - uint8_t *alloc_bitmap; - uint32_t bitmap_blocks, i; - - di = get_prodos_info(image); - - bitmap_blocks = (di->total_blocks + (BLOCK_SIZE * 8) - 1) / (BLOCK_SIZE * 8); - alloc_bitmap = (uint8_t*)malloc(bitmap_blocks * BLOCK_SIZE); - if (!alloc_bitmap) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto done; - } - - for (i = 0; i < bitmap_blocks; i++) - { - err = prodos_load_block(image, di->volume_bitmap_block + i, - &alloc_bitmap[i * BLOCK_SIZE]); - if (err) - goto done; - } - - err = IMGTOOLERR_SUCCESS; - -done: - if (err && alloc_bitmap) - { - free(alloc_bitmap); - alloc_bitmap = NULL; - } - *bitmap = alloc_bitmap; - return err; -} - - - -static imgtoolerr_t prodos_save_volume_bitmap(imgtool::image &image, const uint8_t *bitmap) -{ - imgtoolerr_t err; - prodos_diskinfo *di; - uint32_t bitmap_blocks, i; - - di = get_prodos_info(image); - - bitmap_blocks = (di->total_blocks + (BLOCK_SIZE * 8) - 1) / (BLOCK_SIZE * 8); - - for (i = 0; i < bitmap_blocks; i++) - { - err = prodos_save_block(image, di->volume_bitmap_block + i, - &bitmap[i * BLOCK_SIZE]); - if (err) - return err; - } - return IMGTOOLERR_SUCCESS; -} - - - -static void prodos_set_volume_bitmap_bit(uint8_t *buffer, uint16_t block, int value) -{ - uint8_t mask; - buffer += block / 8; - mask = 1 << (7 - (block % 8)); - if (value) - *buffer |= mask; - else - *buffer &= ~mask; -} - - - -static int prodos_get_volume_bitmap_bit(const uint8_t *buffer, uint16_t block) -{ - uint8_t mask; - buffer += block / 8; - mask = 1 << (7 - (block % 8)); - return (*buffer & mask) ? 1 : 0; -} - - - -static imgtoolerr_t prodos_alloc_block(imgtool::image &image, uint8_t *bitmap, - uint16_t *block) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - prodos_diskinfo *di; - uint16_t bitmap_blocks, i; - uint8_t *alloc_bitmap = NULL; - - di = get_prodos_info(image); - *block = 0; - bitmap_blocks = (di->total_blocks + (BLOCK_SIZE * 8) - 1) / (BLOCK_SIZE * 8); - - if (!bitmap) - { - err = prodos_load_volume_bitmap(image, &alloc_bitmap); - if (err) - goto done; - bitmap = alloc_bitmap; - } - - for (i = (di->volume_bitmap_block + bitmap_blocks); i < di->total_blocks; i++) - { - if (!prodos_get_volume_bitmap_bit(bitmap, i)) - { - prodos_set_volume_bitmap_bit(bitmap, i, 1); - *block = i; - break; - } - } - - if (*block > 0) - { - if (alloc_bitmap) - { - err = prodos_save_volume_bitmap(image, bitmap); - if (err) - goto done; - } - } - else - { - err = IMGTOOLERR_NOSPACE; - } - -done: - if (err) - *block = 0; - if (alloc_bitmap) - free(alloc_bitmap); - return err; -} - - - -/* ----------------------------------------------------------------------- */ - -static imgtoolerr_t prodos_diskimage_create(imgtool::image &image, util::option_resolution *opts) -{ - imgtoolerr_t err; - uint32_t heads, tracks, sectors, sector_bytes; - uint32_t dirent_size, volume_bitmap_block, i; - uint32_t volume_bitmap_block_count, total_blocks; - uint8_t buffer[BLOCK_SIZE]; - - heads = opts->lookup_int('H'); - tracks = opts->lookup_int('T'); - sectors = opts->lookup_int('S'); - sector_bytes = opts->lookup_int('L'); - - dirent_size = 39; - volume_bitmap_block = 6; - total_blocks = tracks * heads * sectors * sector_bytes / BLOCK_SIZE; - volume_bitmap_block_count = (total_blocks + (BLOCK_SIZE * 8) - 1) / (BLOCK_SIZE * 8); - - /* prepare initial dir block */ - memset(buffer, 0, sizeof(buffer)); - place_integer_le(buffer, 4 + 0, 1, 0xF0); - place_integer_le(buffer, 4 + 31, 1, dirent_size); - place_integer_le(buffer, 4 + 32, 1, BLOCK_SIZE / dirent_size); - place_integer_le(buffer, 4 + 35, 2, volume_bitmap_block); - place_integer_le(buffer, 4 + 37, 2, total_blocks); - - err = prodos_save_block(image, ROOTDIR_BLOCK, buffer); - if (err) - return err; - - /* setup volume bitmap */ - memset(buffer, 0, sizeof(buffer)); - for (i = 0; i < (volume_bitmap_block + volume_bitmap_block_count); i++) - prodos_set_volume_bitmap_bit(buffer, i, 1); - prodos_save_block(image, volume_bitmap_block, buffer); - - /* and finally open the image */ - return prodos_diskimage_open(image); -} - - - -static imgtoolerr_t prodos_diskimage_create_525(imgtool::image &image, imgtool::stream::ptr &&dummy, util::option_resolution *opts) -{ - prodos_setprocs_525(image); - return prodos_diskimage_create(image, opts); -} - - - -static imgtoolerr_t prodos_diskimage_create_35(imgtool::image &image, imgtool::stream::ptr &&dummy, util::option_resolution *opts) -{ - prodos_setprocs_35(image); - return prodos_diskimage_create(image, opts); -} - - - -/* ----------------------------------------------------------------------- */ - -static imgtoolerr_t prodos_enum_seek(imgtool::image &image, - prodos_direnum *appleenum, uint32_t block, uint32_t index) -{ - imgtoolerr_t err; - uint8_t buffer[BLOCK_SIZE]; - - if (appleenum->block != block) - { - if (block != 0) - { - err = prodos_load_block(image, block, buffer); - if (err) - return err; - memcpy(appleenum->block_data, buffer, sizeof(buffer)); - } - appleenum->block = block; - } - - appleenum->index = index; - return IMGTOOLERR_SUCCESS; -} - - - -static uint8_t *next_info_block(uint8_t *buffer, size_t *position) -{ - size_t side = *position & 0x100; - size_t subpos = *position & 0x0FF; - uint8_t *result; - - if (subpos < 8) - { - subpos = 8; - *position = side + subpos; - } - - while((buffer[side + subpos] == 0x00) || (subpos + buffer[side + subpos] > 0x100)) - { - if (side) - return NULL; - - side = 0x100; - subpos = 8; - } - - result = &buffer[side + subpos]; - subpos += *result; - *position = side + subpos; - return result; -} - - - -static uint8_t *alloc_info_block(uint8_t *buffer, size_t block_size, uint8_t block_type) -{ - size_t position = 0; - size_t side; - size_t subpos; - uint8_t *result; - - while(next_info_block(buffer, &position)) - ; - - side = position & 0x100; - subpos = position & 0x0FF; - - if ((subpos + block_size) > 0x100) - return NULL; - - result = &buffer[side + subpos]; - *(result++) = (uint8_t) block_size; - *(result++) = block_type; - memset(result, 0, block_size - 2); - return result; -} - - - -static imgtoolerr_t prodos_get_next_dirent(imgtool::image &image, - prodos_direnum *appleenum, prodos_dirent &ent) -{ - imgtoolerr_t err; - prodos_diskinfo *di; - size_t finfo_offset; - uint32_t next_block, next_index; - uint32_t offset; - uint8_t buffer[BLOCK_SIZE]; - const uint8_t *info_ptr; - int fork_num; - - di = get_prodos_info(image); - memset(&ent, 0, sizeof(ent)); - - /* have we hit the end of the file? */ - if (appleenum->block == 0) - return IMGTOOLERR_SUCCESS; - - /* populate the resulting dirent */ - offset = appleenum->index * di->dirent_size + 4; - ent.storage_type = appleenum->block_data[offset + 0]; - memcpy(ent.filename, &appleenum->block_data[offset + 1], 15); - ent.filename[15] = '\0'; - ent.creation_time = pick_integer_le(appleenum->block_data, offset + 24, 4); - ent.lastmodified_time = pick_integer_le(appleenum->block_data, offset + 33, 4); - ent.file_type = 0x3F3F3F3F; - ent.file_creator = 0x3F3F3F3F; - ent.finder_flags = 0; - ent.coord_x = 0; - ent.coord_y = 0; - ent.finder_folder = 0; - ent.icon_id = 0; - ent.script_code = 0; - ent.extended_flags = 0; - ent.comment_id = 0; - ent.putaway_directory = 0; - - if (is_extendedfile_storagetype(ent.storage_type)) - { - /* this is a ProDOS extended file; we need to get the extended info - * block */ - ent.extkey_pointer = pick_integer_le(appleenum->block_data, offset + 17, 2); - - err = prodos_load_block(image, ent.extkey_pointer, buffer); - if (err) - return err; - - for (fork_num = 0; fork_num <= 1; fork_num++) - { - ent.key_pointer[fork_num] = pick_integer_le(buffer, 1 + (fork_num * 256), 2); - ent.filesize[fork_num] = pick_integer_le(buffer, 5 + (fork_num * 256), 3); - ent.depth[fork_num] = buffer[fork_num * 256] & 0x0F; - } - - finfo_offset = 0; - while((info_ptr = next_info_block(buffer, &finfo_offset)) != NULL) - { - if (*(info_ptr++) == 18) - { - switch(*(info_ptr++)) - { - case 1: /* FInfo */ - ent.file_type = pick_integer_be(info_ptr, 0, 4); - ent.file_creator = pick_integer_be(info_ptr, 4, 4); - ent.finder_flags = pick_integer_be(info_ptr, 8, 2); - ent.coord_x = pick_integer_be(info_ptr, 10, 2); - ent.coord_y = pick_integer_be(info_ptr, 12, 2); - ent.finder_folder = pick_integer_be(info_ptr, 14, 4); - break; - - case 2: /* xFInfo */ - ent.icon_id = pick_integer_be(info_ptr, 0, 2); - ent.script_code = pick_integer_be(info_ptr, 8, 1); - ent.extended_flags = pick_integer_be(info_ptr, 9, 1); - ent.comment_id = pick_integer_be(info_ptr, 10, 2); - ent.putaway_directory = pick_integer_be(info_ptr, 12, 4); - break; - } - } - } - } - else - { - /* normal ProDOS files have all of the info right here */ - ent.key_pointer[0] = pick_integer_le(appleenum->block_data, offset + 17, 2); - ent.filesize[0] = pick_integer_le(appleenum->block_data, offset + 21, 3); - ent.depth[0] = ent.storage_type >> 4; - } - - /* identify next entry */ - next_block = appleenum->block; - next_index = appleenum->index + 1; - if (next_index >= di->dirents_per_block) - { - next_block = pick_integer_le(appleenum->block_data, 2, 2); - next_index = 0; - } - - /* seek next block */ - err = prodos_enum_seek(image, appleenum, next_block, next_index); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - - -/* changes a normal file to a ProDOS extended file */ -static imgtoolerr_t prodos_promote_file(imgtool::image &image, uint8_t *bitmap, prodos_dirent *ent) -{ - imgtoolerr_t err; - uint16_t new_block; - uint8_t buffer[BLOCK_SIZE]; - - assert(is_normalfile_storagetype(ent->storage_type)); - - err = prodos_alloc_block(image, bitmap, &new_block); - if (err) - return err; - - /* create raw extended info block */ - memset(buffer, 0, sizeof(buffer)); - err = prodos_save_block(image, new_block, buffer); - if (err) - return err; - - ent->storage_type = (ent->storage_type & 0x0F) | 0x50; - ent->extkey_pointer = new_block; - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_put_dirent(imgtool::image &image, - prodos_direnum *appleenum, prodos_dirent *ent) -{ - imgtoolerr_t err; - prodos_diskinfo *di; - uint32_t offset; - size_t finfo_offset; - uint8_t buffer[BLOCK_SIZE]; - int fork_num; - int needs_finfo = false; - int needs_xfinfo = false; - uint8_t *info_ptr; - uint8_t *finfo; - uint8_t *xfinfo; - - di = get_prodos_info(image); - offset = appleenum->index * di->dirent_size + 4; - - /* determine whether we need FInfo and/or xFInfo */ - if (is_normalfile_storagetype(ent->storage_type)) - { - needs_finfo = (ent->file_type != 0x3F3F3F3F) || - (ent->file_creator != 0x3F3F3F3F) || - (ent->finder_flags != 0) || - (ent->coord_x != 0) || - (ent->coord_y != 0) || - (ent->finder_folder != 0); - - needs_xfinfo = (ent->icon_id != 0) || - (ent->script_code != 0) || - (ent->extended_flags != 0) || - (ent->comment_id != 0) || - (ent->putaway_directory != 0); - } - - /* do we need to promote this file to an extended file? */ - if (!is_extendedfile_storagetype(ent->storage_type) - && (needs_finfo || needs_xfinfo)) - { - err = prodos_promote_file(image, NULL, ent); - if (err) - return err; - } - - /* write out the storage type, filename, creation and lastmodified times */ - appleenum->block_data[offset + 0] = ent->storage_type; - memcpy(&appleenum->block_data[offset + 1], ent->filename, 15); - place_integer_le(appleenum->block_data, offset + 24, 4, ent->creation_time); - place_integer_le(appleenum->block_data, offset + 33, 4, ent->lastmodified_time); - - if (is_extendedfile_storagetype(ent->storage_type)) - { - /* ProDOS extended file */ - err = prodos_load_block(image, ent->extkey_pointer, buffer); - if (err) - return err; - - finfo = NULL; - xfinfo = NULL; - - for (fork_num = 0; fork_num <= 1; fork_num++) - { - place_integer_le(buffer, 1 + (fork_num * 256), 2, ent->key_pointer[fork_num]); - place_integer_le(buffer, 5 + (fork_num * 256), 3, ent->filesize[fork_num]); - buffer[fork_num * 256] = ent->depth[fork_num]; - } - - finfo_offset = 0; - while((info_ptr = next_info_block(buffer, &finfo_offset)) != NULL) - { - if (*(info_ptr++) == 18) - { - switch(*(info_ptr++)) - { - case 1: /* FInfo */ - finfo = info_ptr; - break; - - case 2: /* xFInfo */ - xfinfo = info_ptr; - break; - } - } - } - - /* allocate the finfo and/or xinfo blocks, if we need them */ - if (needs_finfo && !finfo) - finfo = alloc_info_block(buffer, 18, 1); - if (needs_xfinfo && !xfinfo) - xfinfo = alloc_info_block(buffer, 18, 2); - - if (finfo) - { - place_integer_be(finfo, 0, 4, ent->file_type); - place_integer_be(finfo, 4, 4, ent->file_creator); - place_integer_be(finfo, 8, 2, ent->finder_flags); - place_integer_be(finfo, 10, 2, ent->coord_x); - place_integer_be(finfo, 12, 2, ent->coord_y); - place_integer_be(finfo, 14, 4, ent->finder_folder); - } - - if (xfinfo) - { - place_integer_be(xfinfo, 0, 2, ent->icon_id); - place_integer_be(xfinfo, 8, 1, ent->script_code); - place_integer_be(xfinfo, 9, 1, ent->extended_flags); - place_integer_be(xfinfo, 10, 2, ent->comment_id); - place_integer_be(xfinfo, 12, 4, ent->putaway_directory); - } - - err = prodos_save_block(image, ent->extkey_pointer, buffer); - if (err) - return err; - - place_integer_le(appleenum->block_data, offset + 17, 2, ent->extkey_pointer); - place_integer_le(appleenum->block_data, offset + 21, 3, BLOCK_SIZE); - } - else - { - /* normal file */ - place_integer_le(appleenum->block_data, offset + 17, 2, ent->key_pointer[0]); - place_integer_le(appleenum->block_data, offset + 21, 3, ent->filesize[0]); - } - - err = prodos_save_block(image, appleenum->block, appleenum->block_data); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_lookup_path(imgtool::image &image, const char *path, - creation_policy_t create, prodos_direnum *direnum, prodos_dirent *ent) -{ - imgtoolerr_t err; - prodos_direnum my_direnum; - uint32_t block = ROOTDIR_BLOCK; - const char *old_path; - uint16_t this_block; - uint32_t this_index; - uint16_t free_block = 0; - uint32_t free_index = 0; - uint16_t new_file_block; - uint8_t buffer[BLOCK_SIZE]; - - if (!direnum) - direnum = &my_direnum; - - while(*path) - { - memset(direnum, 0, sizeof(*direnum)); - err = prodos_enum_seek(image, direnum, block, 0); - if (err) - goto done; - - do - { - this_block = direnum->block; - this_index = direnum->index; - - err = prodos_get_next_dirent(image, direnum, *ent); - if (err) - goto done; - - /* if we need to create a file entry and this is free, track it */ - if (create && this_block && !free_block && !ent->storage_type) - { - free_block = this_block; - free_index = this_index; - } - } - while(direnum->block && (strcmp(path, ent->filename) || ( - !is_file_storagetype(ent->storage_type) && - !is_dir_storagetype(ent->storage_type)))); - - old_path = path; - path += strlen(path) + 1; - if (*path) - { - /* we have found part of the path; we are not finished yet */ - if (!is_dir_storagetype(ent->storage_type)) - { - err = IMGTOOLERR_FILENOTFOUND; - goto done; - } - block = ent->key_pointer[0]; - } - else if (!direnum->block) - { - /* did not find file; maybe we need to create it */ - if (create == CREATE_NONE) - { - err = IMGTOOLERR_FILENOTFOUND; - goto done; - } - - /* do we need to expand the directory? */ - if (!free_block) - { - if (this_block == 0) - { - err = IMGTOOLERR_CORRUPTFILE; - goto done; - } - - err = prodos_load_block(image, this_block, buffer); - if (err) - goto done; - - /* allocate a block */ - err = prodos_alloc_block(image, NULL, &free_block); - if (err) - goto done; - - /* clear out this new block */ - err = prodos_clear_block(image, free_block); - if (err) - goto done; - - /* save this link */ - place_integer_le(buffer, 2, 2, free_block); - err = prodos_save_block(image, this_block, buffer); - if (err) - goto done; - - free_index = 0; - } - - /* seek back to the free space */ - err = prodos_enum_seek(image, direnum, free_block, free_index); - if (err) - goto done; - - new_file_block = 0; - if (create == CREATE_DIR) - { - /* if we are creating a directory, we need to create a new block */ - err = prodos_alloc_block(image, NULL, &new_file_block); - if (err) - goto done; - - err = prodos_clear_block(image, new_file_block); - if (err) - goto done; - } - - /* prepare the dirent */ - memset(ent, 0, sizeof(*ent)); - ent->storage_type = (create == CREATE_DIR) ? 0xe0 : 0x10; - ent->creation_time = ent->lastmodified_time = prodos_time_now(); - ent->key_pointer[0] = new_file_block; - ent->file_type = 0x3F3F3F3F; - ent->file_creator = 0x3F3F3F3F; - strncpy(ent->filename, old_path, ARRAY_LENGTH(ent->filename)); - - /* and place it */ - err = prodos_put_dirent(image, direnum, ent); - if (err) - goto done; - - this_block = free_block; - this_index = free_index; - } - else - { - /* we've found the file; seek that dirent */ - err = prodos_enum_seek(image, direnum, this_block, this_index); - if (err) - goto done; - } - } - - err = IMGTOOLERR_SUCCESS; -done: - return err; -} - - - -static imgtoolerr_t prodos_fill_file(imgtool::image &image, uint8_t *bitmap, - uint16_t key_block, int key_block_allocated, - int depth, uint32_t blockcount, uint32_t block_index) -{ - imgtoolerr_t err; - prodos_diskinfo *di; - int dirty; - int sub_block_allocated; - uint16_t i, sub_block, new_sub_block; - uint8_t buffer[BLOCK_SIZE]; - - di = get_prodos_info(image); - - if (key_block_allocated) - { - /* we are on a recently allocated key block; start fresh */ - memset(buffer, 0, sizeof(buffer)); - dirty = true; - } - else - { - /* this is a preexisting key block */ - err = prodos_load_block(image, key_block, buffer); - if (err) - return err; - dirty = false; - } - - for (i = 0; i < 256; i++) - { - sub_block_allocated = false; - - sub_block = buffer[i + 256]; - sub_block <<= 8; - sub_block += buffer[i + 0]; - - new_sub_block = sub_block; - if ((block_index < blockcount) && (sub_block == 0)) - { - err = prodos_alloc_block(image, bitmap, &new_sub_block); - if (err) - return err; - sub_block_allocated = true; - } - else if ((block_index >= blockcount) && (sub_block != 0)) - { - new_sub_block = 0; - if (sub_block < di->total_blocks) - prodos_set_volume_bitmap_bit(bitmap, sub_block, 0); - } - - /* did we change the block? */ - if (new_sub_block != sub_block) - { - dirty = true; - buffer[i + 0] = new_sub_block >> 0; - buffer[i + 256] = new_sub_block >> 8; - if (sub_block == 0) - sub_block = new_sub_block; - } - - /* call recursive function */ - if (depth > 2) - { - err = prodos_fill_file(image, bitmap, sub_block, sub_block_allocated, depth - 1, blockcount, block_index); - if (err) - return err; - } - - /* increment index */ - block_index += 1 << ((depth - 2) * 8); - } - - /* if we changed anything, then save the block */ - if (dirty) - { - err = prodos_save_block(image, key_block, buffer); - if (err) - return err; - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_set_file_block_count(imgtool::image &image, prodos_direnum *direnum, - prodos_dirent *ent, uint8_t *bitmap, int fork_num, uint32_t new_blockcount) -{ - imgtoolerr_t err; - int depth, new_depth, i; - uint16_t new_block, block; - uint8_t buffer[BLOCK_SIZE]; - uint16_t key_pointer; - - if (fork_num && (new_blockcount > 0) && !is_extendedfile_storagetype(ent->storage_type)) - { - /* need to change a normal file to an extended file */ - err = prodos_promote_file(image, bitmap, ent); - if (err) - return err; - } - - key_pointer = ent->key_pointer[fork_num]; - depth = ent->depth[fork_num]; - - /* determine the new tree depth */ - if (new_blockcount <= 1) - new_depth = 1; - else if (new_blockcount <= 256) - new_depth = 2; - else - new_depth = 3; - - /* are we zero length, and do we have to create a block? */ - if ((new_blockcount >= 1) && (key_pointer == 0)) - { - err = prodos_alloc_block(image, bitmap, &new_block); - if (err) - return err; - key_pointer = new_block; - } - - /* do we have to grow the tree? */ - while(new_depth > depth) - { - err = prodos_alloc_block(image, bitmap, &new_block); - if (err) - return err; - - /* create this new key block, with a link to the previous one */ - memset(buffer, 0, sizeof(buffer)); - buffer[0] = (uint8_t) (key_pointer >> 0); - buffer[256] = (uint8_t) (key_pointer >> 8); - err = prodos_save_block(image, new_block, buffer); - if (err) - return err; - - depth++; - key_pointer = new_block; - } - - /* do we have to shrink the tree? */ - while(new_depth < depth) - { - err = prodos_load_block(image, key_pointer, buffer); - if (err) - return err; - - for (i = 1; i < 256; i++) - { - block = buffer[i + 256]; - block <<= 8; - block |= buffer[i + 0]; - - if (block > 0) - { - if (depth > 2) - { - /* remove this block's children */ - err = prodos_fill_file(image, bitmap, block, false, depth - 1, 0, 0); - if (err) - return err; - } - - /* and remove this block */ - prodos_set_volume_bitmap_bit(bitmap, block, 0); - } - } - - /* remove this key block */ - prodos_set_volume_bitmap_bit(bitmap, key_pointer, 0); - - /* set the new key pointer */ - block = buffer[256]; - block <<= 8; - block |= buffer[0]; - key_pointer = block; - - depth--; - } - - if (new_blockcount > 0) - { - /* fill out the file tree */ - err = prodos_fill_file(image, bitmap, key_pointer, false, depth, new_blockcount, 0); - if (err) - return err; - } - else if (key_pointer != 0) - { - /* we are now zero length, and don't need a key pointer */ - prodos_set_volume_bitmap_bit(bitmap, key_pointer, 0); - key_pointer = 0; - } - - /* change the depth if we are not an extended file */ - if (is_normalfile_storagetype(ent->storage_type)) - { - ent->storage_type &= ~0xF0; - ent->storage_type |= depth * 0x10; - } - - ent->key_pointer[fork_num] = key_pointer; - ent->depth[fork_num] = depth; - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_set_file_size(imgtool::image &image, prodos_direnum *direnum, - prodos_dirent *ent, int fork_num, uint32_t new_size) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - uint32_t blockcount, new_blockcount; - uint8_t *bitmap = NULL; - - if (ent->filesize[fork_num] != new_size) - { - blockcount = (ent->filesize[fork_num] + BLOCK_SIZE - 1) / BLOCK_SIZE; - new_blockcount = (new_size + BLOCK_SIZE - 1) / BLOCK_SIZE; - - /* do we need to change the block chain? */ - if (new_blockcount != blockcount) - { - err = prodos_load_volume_bitmap(image, &bitmap); - if (err) - goto done; - - err = prodos_set_file_block_count(image, direnum, ent, bitmap, fork_num, new_blockcount); - if (err) - goto done; - - err = prodos_save_volume_bitmap(image, bitmap); - if (err) - goto done; - } - - ent->filesize[fork_num] = new_size; - err = prodos_put_dirent(image, direnum, ent); - if (err) - goto done; - } - -done: - if (bitmap) - free(bitmap); - return err; -} - - - -static uint32_t prodos_get_storagetype_maxfilesize(uint8_t storage_type) -{ - uint32_t max_filesize = 0; - switch(storage_type & 0xF0) - { - case 0x10: - max_filesize = BLOCK_SIZE * 1; - break; - case 0x20: - max_filesize = BLOCK_SIZE * 256; - break; - case 0x30: - case 0x50: - max_filesize = BLOCK_SIZE * 32768; - break; - } - return max_filesize; -} - - - -static imgtoolerr_t prodos_diskimage_beginenum(imgtool::directory &enumeration, const char *path) -{ - imgtoolerr_t err; - imgtool::image &image(enumeration.image()); - prodos_direnum *appleenum; - prodos_dirent ent; - uint16_t block = ROOTDIR_BLOCK; - - appleenum = (prodos_direnum *) enumeration.extra_bytes(); - - /* find subdirectory, if appropriate */ - if (*path) - { - err = prodos_lookup_path(image, path, CREATE_NONE, NULL, &ent); - if (err) - return err; - - /* only work on directories */ - if (!is_dir_storagetype(ent.storage_type)) - return IMGTOOLERR_FILENOTFOUND; - - block = ent.key_pointer[0]; - } - - /* seek initial block */ - err = prodos_enum_seek(image, appleenum, block, 0); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_diskimage_nextenum(imgtool::directory &enumeration, imgtool_dirent &ent) -{ - imgtoolerr_t err; - imgtool::image &image(enumeration.image()); - prodos_direnum *appleenum; - prodos_dirent pd_ent; - uint32_t max_filesize; - - appleenum = (prodos_direnum *) enumeration.extra_bytes(); - - do - { - err = prodos_get_next_dirent(image, appleenum, pd_ent); - if (err) - return err; - } - while(appleenum->block - && !is_file_storagetype(pd_ent.storage_type) - && !is_dir_storagetype(pd_ent.storage_type)); - - /* end of file? */ - if (pd_ent.storage_type == 0x00) - { - ent.eof = 1; - return IMGTOOLERR_SUCCESS; - } - - strcpy(ent.filename, pd_ent.filename); - ent.directory = is_dir_storagetype(pd_ent.storage_type); - ent.creation_time = prodos_crack_time(pd_ent.creation_time); - ent.lastmodified_time = prodos_crack_time(pd_ent.lastmodified_time); - - if (!ent.directory) - { - ent.filesize = pd_ent.filesize[0]; - - max_filesize = prodos_get_storagetype_maxfilesize(pd_ent.storage_type); - if (ent.filesize > max_filesize) - { - ent.corrupt = 1; - ent.filesize = max_filesize; - } - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_read_file_tree(imgtool::image &image, uint32_t *filesize, - uint32_t block, int nest_level, imgtool::stream &destf) -{ - imgtoolerr_t err; - prodos_diskinfo *di; - uint8_t buffer[BLOCK_SIZE]; - uint16_t sub_block; - size_t bytes_to_write; - int i; - - /* check bounds */ - di = get_prodos_info(image); - if (block >= di->total_blocks) - return IMGTOOLERR_CORRUPTFILE; - - err = prodos_load_block(image, block, buffer); - if (err) - return err; - - if (nest_level > 0) - { - /* this is an index block */ - for (i = 0; i < 256; i++) - { - /* retrieve the block pointer; the two bytes are on either half - * of the block */ - sub_block = buffer[i + 256]; - sub_block <<= 8; - sub_block |= buffer[i + 0]; - - if (sub_block != 0) - { - err = prodos_read_file_tree(image, filesize, sub_block, nest_level - 1, destf); - if (err) - return err; - } - } - } - else - { - /* this is a leaf block */ - bytes_to_write = std::min(size_t(*filesize), sizeof(buffer)); - destf.write(buffer, bytes_to_write); - *filesize -= bytes_to_write; - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_write_file_tree(imgtool::image &image, uint32_t *filesize, - uint32_t block, int nest_level, imgtool::stream &sourcef) -{ - imgtoolerr_t err; - prodos_diskinfo *di; - uint8_t buffer[BLOCK_SIZE]; - uint16_t sub_block; - size_t bytes_to_read; - int i; - - /* nothing more to read? bail */ - if (*filesize == 0) - return IMGTOOLERR_SUCCESS; - - /* check bounds */ - di = get_prodos_info(image); - if (block >= di->total_blocks) - return IMGTOOLERR_CORRUPTFILE; - - err = prodos_load_block(image, block, buffer); - if (err) - return err; - - if (nest_level > 0) - { - for (i = 0; i < 256; i++) - { - sub_block = buffer[i + 256]; - sub_block <<= 8; - sub_block |= buffer[i + 0]; - - if (sub_block != 0) - { - err = prodos_write_file_tree(image, filesize, sub_block, nest_level - 1, sourcef); - if (err) - return err; - } - } - } - else - { - /* this is a leaf block */ - bytes_to_read = std::min(size_t(*filesize), sizeof(buffer)); - sourcef.read(buffer, bytes_to_read); - *filesize -= bytes_to_read; - - err = prodos_save_block(image, block, buffer); - if (err) - return err; - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_diskimage_freespace(imgtool::partition &partition, uint64_t *size) -{ - imgtoolerr_t err; - imgtool::image &image(partition.image()); - prodos_diskinfo *di; - uint8_t *bitmap = NULL; - uint16_t i; - - di = get_prodos_info(image); - *size = 0; - - err = prodos_load_volume_bitmap(image, &bitmap); - if (err) - goto done; - - for (i = 0; i < di->total_blocks; i++) - { - if (!prodos_get_volume_bitmap_bit(bitmap, i)) - *size += BLOCK_SIZE; - } - -done: - if (bitmap) - free(bitmap); - return err; -} - - - -static imgtoolerr_t prodos_diskimage_readfile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &destf) -{ - imgtoolerr_t err; - imgtool::image &image(partition.image()); - prodos_dirent ent; - uint16_t key_pointer; - int nest_level; - mac_fork_t fork_num; - - err = prodos_lookup_path(image, filename, CREATE_NONE, NULL, &ent); - if (err) - return err; - - if (is_dir_storagetype(ent.storage_type)) - return IMGTOOLERR_FILENOTFOUND; - - err = mac_identify_fork(fork, &fork_num); - if (err) - return err; - - key_pointer = ent.key_pointer[fork_num]; - nest_level = ent.depth[fork_num] - 1; - - if (key_pointer != 0) - { - err = prodos_read_file_tree(image, &ent.filesize[fork_num], key_pointer, - nest_level, destf); - if (err) - return err; - } - - /* have we not actually received the correct amount of bytes? if not, fill in the rest */ - if (ent.filesize[fork_num] > 0) - destf.fill(0, ent.filesize[fork_num]); - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_diskimage_writefile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &sourcef, util::option_resolution *opts) -{ - imgtoolerr_t err; - imgtool::image &image(partition.image()); - prodos_dirent ent; - prodos_direnum direnum; - uint64_t file_size; - mac_fork_t fork_num; - - file_size = sourcef.size(); - - err = prodos_lookup_path(image, filename, CREATE_FILE, &direnum, &ent); - if (err) - return err; - - /* only work on files */ - if (is_dir_storagetype(ent.storage_type)) - return IMGTOOLERR_FILENOTFOUND; - - err = mac_identify_fork(fork, &fork_num); - if (err) - return err; - - /* set the file size */ - err = prodos_set_file_size(image, &direnum, &ent, fork_num, file_size); - if (err) - return err; - - err = prodos_write_file_tree(image, &ent.filesize[fork_num], ent.key_pointer[fork_num], - ent.depth[fork_num] - 1, sourcef); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_diskimage_deletefile(imgtool::partition &partition, const char *path) -{ - imgtoolerr_t err; - imgtool::image &image(partition.image()); - prodos_dirent ent; - prodos_direnum direnum; - - err = prodos_lookup_path(image, path, CREATE_NONE, &direnum, &ent); - if (err) - return err; - - /* only work on files */ - if (is_dir_storagetype(ent.storage_type)) - return IMGTOOLERR_FILENOTFOUND; - - /* empty out both forks */ - err = prodos_set_file_size(image, &direnum, &ent, 0, 0); - if (err) - return err; - err = prodos_set_file_size(image, &direnum, &ent, 1, 0); - if (err) - return err; - - memset(&ent, 0, sizeof(ent)); - err = prodos_put_dirent(image, &direnum, &ent); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_diskimage_listforks(imgtool::partition &partition, const char *path, std::vector<imgtool::fork_entry> &forks) -{ - imgtoolerr_t err; - imgtool::image &image(partition.image()); - prodos_dirent ent; - prodos_direnum direnum; - - err = prodos_lookup_path(image, path, CREATE_NONE, &direnum, &ent); - if (err) - return err; - - if (is_dir_storagetype(ent.storage_type)) - return IMGTOOLERR_FILENOTFOUND; - - // specify data fork - forks.emplace_back(ent.filesize[0], imgtool::fork_entry::type_t::DATA); - - if (is_extendedfile_storagetype(ent.storage_type)) - { - // specify the resource fork - forks.emplace_back(ent.filesize[1], imgtool::fork_entry::type_t::RESOURCE); - } - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_diskimage_createdir(imgtool::partition &partition, const char *path) -{ - imgtoolerr_t err; - imgtool::image &image(partition.image()); - prodos_dirent ent; - prodos_direnum direnum; - - err = prodos_lookup_path(image, path, CREATE_DIR, &direnum, &ent); - if (err) - return err; - - /* only work on directories */ - if (!is_dir_storagetype(ent.storage_type)) - return IMGTOOLERR_FILENOTFOUND; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_free_directory(imgtool::image &image, uint8_t *volume_bitmap, uint16_t key_pointer) -{ - imgtoolerr_t err; - prodos_diskinfo *di; - int i; - uint16_t next_block; - uint32_t offset; - uint8_t buffer[BLOCK_SIZE]; - - di = get_prodos_info(image); - - if (key_pointer != 0) - { - err = prodos_load_block(image, key_pointer, buffer); - if (err) - return err; - - for (i = 0; i < di->dirents_per_block; i++) - { - offset = i * di->dirent_size + 4; - - if (is_file_storagetype(buffer[offset]) || is_file_storagetype(buffer[offset])) - return IMGTOOLERR_DIRNOTEMPTY; - } - - next_block = pick_integer_le(buffer, 2, 2); - - err = prodos_free_directory(image, volume_bitmap, next_block); - if (err) - return err; - - prodos_set_volume_bitmap_bit(volume_bitmap, key_pointer, 0); - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_diskimage_deletedir(imgtool::partition &partition, const char *path) -{ - imgtoolerr_t err; - imgtool::image &image(partition.image()); - prodos_dirent ent; - prodos_direnum direnum; - uint8_t *volume_bitmap = NULL; - - err = prodos_lookup_path(image, path, CREATE_NONE, &direnum, &ent); - if (err) - goto done; - - /* only work on directories */ - if (!is_dir_storagetype(ent.storage_type)) - { - err = IMGTOOLERR_FILENOTFOUND; - goto done; - } - - err = prodos_load_volume_bitmap(image, &volume_bitmap); - if (err) - goto done; - - err = prodos_free_directory(image, volume_bitmap, ent.key_pointer[0]); - if (err) - goto done; - - err = prodos_save_volume_bitmap(image, volume_bitmap); - if (err) - goto done; - - memset(&ent, 0, sizeof(ent)); - err = prodos_put_dirent(image, &direnum, &ent); - if (err) - goto done; - -done: - if (volume_bitmap) - free(volume_bitmap); - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_get_file_tree(imgtool::image &image, imgtool_chainent *chain, size_t chain_size, - size_t *chain_pos, uint16_t block, uint8_t total_depth, uint8_t cur_depth) -{ - imgtoolerr_t err; - prodos_diskinfo *di; - int i; - uint16_t sub_block; - uint8_t buffer[BLOCK_SIZE]; - - if (block == 0) - return IMGTOOLERR_SUCCESS; - if (*chain_pos >= chain_size) - return IMGTOOLERR_SUCCESS; - - /* check bounds */ - di = get_prodos_info(image); - if (block >= di->total_blocks) - return IMGTOOLERR_CORRUPTFILE; - - chain[*chain_pos].level = cur_depth; - chain[*chain_pos].block = block; - (*chain_pos)++; - - /* must we recurse into the tree? */ - if (cur_depth < total_depth) - { - err = prodos_load_block(image, block, buffer); - if (err) - return err; - - for (i = 0; i < 256; i++) - { - sub_block = buffer[i + 256]; - sub_block <<= 8; - sub_block |= buffer[i + 0]; - - err = prodos_get_file_tree(image, chain, chain_size, chain_pos, sub_block, total_depth, cur_depth + 1); - if (err) - return err; - } - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_diskimage_getattrs(imgtool::partition &partition, const char *path, const uint32_t *attrs, imgtool_attribute *values) -{ - imgtoolerr_t err; - imgtool::image &image(partition.image()); - prodos_dirent ent; - int i; - - err = prodos_lookup_path(image, path, CREATE_NONE, NULL, &ent); - if (err) - return err; - - for (i = 0; attrs[i]; i++) - { - switch(attrs[i]) - { - case IMGTOOLATTR_INT_MAC_TYPE: - values[i].i = ent.file_type; - break; - case IMGTOOLATTR_INT_MAC_CREATOR: - values[i].i = ent.file_creator; - break; - case IMGTOOLATTR_INT_MAC_FINDERFLAGS: - values[i].i = ent.finder_flags; - break; - case IMGTOOLATTR_INT_MAC_COORDX: - values[i].i = ent.coord_x; - break; - case IMGTOOLATTR_INT_MAC_COORDY: - values[i].i = ent.coord_y; - break; - case IMGTOOLATTR_INT_MAC_FINDERFOLDER: - values[i].i = ent.finder_folder; - break; - case IMGTOOLATTR_INT_MAC_ICONID: - values[i].i = ent.icon_id; - break; - case IMGTOOLATTR_INT_MAC_SCRIPTCODE: - values[i].i = ent.script_code; - break; - case IMGTOOLATTR_INT_MAC_EXTENDEDFLAGS: - values[i].i = ent.extended_flags; - break; - case IMGTOOLATTR_INT_MAC_COMMENTID: - values[i].i = ent.comment_id; - break; - case IMGTOOLATTR_INT_MAC_PUTAWAYDIRECTORY: - values[i].i = ent.putaway_directory; - break; - - case IMGTOOLATTR_TIME_CREATED: - values[i].t = prodos_crack_time(ent.creation_time).to_time_t(); - break; - case IMGTOOLATTR_TIME_LASTMODIFIED: - values[i].t = prodos_crack_time(ent.lastmodified_time).to_time_t(); - break; - } - } - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_diskimage_setattrs(imgtool::partition &partition, const char *path, const uint32_t *attrs, const imgtool_attribute *values) -{ - imgtoolerr_t err; - imgtool::image &image(partition.image()); - prodos_dirent ent; - prodos_direnum direnum; - int i; - - err = prodos_lookup_path(image, path, CREATE_NONE, &direnum, &ent); - if (err) - return err; - - for (i = 0; attrs[i]; i++) - { - switch(attrs[i]) - { - case IMGTOOLATTR_INT_MAC_TYPE: - ent.file_type = values[i].i; - break; - case IMGTOOLATTR_INT_MAC_CREATOR: - ent.file_creator = values[i].i; - break; - case IMGTOOLATTR_INT_MAC_FINDERFLAGS: - ent.finder_flags = values[i].i; - break; - case IMGTOOLATTR_INT_MAC_COORDX: - ent.coord_x = values[i].i; - break; - case IMGTOOLATTR_INT_MAC_COORDY: - ent.coord_y = values[i].i; - break; - case IMGTOOLATTR_INT_MAC_FINDERFOLDER: - ent.finder_folder = values[i].i; - break; - case IMGTOOLATTR_INT_MAC_ICONID: - ent.icon_id = values[i].i; - break; - case IMGTOOLATTR_INT_MAC_SCRIPTCODE: - ent.script_code = values[i].i; - break; - case IMGTOOLATTR_INT_MAC_EXTENDEDFLAGS: - ent.extended_flags = values[i].i; - break; - case IMGTOOLATTR_INT_MAC_COMMENTID: - ent.comment_id = values[i].i; - break; - case IMGTOOLATTR_INT_MAC_PUTAWAYDIRECTORY: - ent.putaway_directory = values[i].i; - break; - - case IMGTOOLATTR_TIME_CREATED: - ent.creation_time = prodos_setup_time(values[i].t); - break; - case IMGTOOLATTR_TIME_LASTMODIFIED: - ent.lastmodified_time = prodos_setup_time(values[i].t); - break; - } - } - - err = prodos_put_dirent(image, &direnum, &ent); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_diskimage_suggesttransfer(imgtool::partition &partition, const char *path, imgtool_transfer_suggestion *suggestions, size_t suggestions_length) -{ - imgtoolerr_t err; - imgtool::image &image(partition.image()); - prodos_dirent ent; - mac_filecategory_t file_category = MAC_FILECATEGORY_DATA; - - if (path) - { - err = prodos_lookup_path(image, path, CREATE_NONE, NULL, &ent); - if (err) - return err; - - file_category = is_extendedfile_storagetype(ent.storage_type) - ? MAC_FILECATEGORY_FORKED : MAC_FILECATEGORY_DATA; - } - - mac_suggest_transfer(file_category, suggestions, suggestions_length); - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_diskimage_getchain(imgtool::partition &partition, const char *path, imgtool_chainent *chain, size_t chain_size) -{ - imgtoolerr_t err; - imgtool::image &image(partition.image()); - prodos_dirent ent; - size_t chain_pos = 0; - int fork_num; - - err = prodos_lookup_path(image, path, CREATE_NONE, NULL, &ent); - if (err) - return err; - - switch(ent.storage_type & 0xF0) - { - case 0x10: - case 0x20: - case 0x30: - /* normal ProDOS file */ - err = prodos_get_file_tree(image, chain, chain_size, &chain_pos, - ent.key_pointer[0], ent.depth[0] - 1, 0); - if (err) - return err; - break; - - case 0x50: - /* extended ProDOS file */ - chain[chain_pos].level = 0; - chain[chain_pos].block = ent.extkey_pointer; - chain_pos++; - - for (fork_num = 0; fork_num <= 1; fork_num++) - { - if (ent.key_pointer[fork_num]) - { - err = prodos_get_file_tree(image, chain, chain_size, &chain_pos, - ent.key_pointer[fork_num], ent.depth[fork_num] - 1, 1); - if (err) - return err; - } - } - break; - - case 0xE0: - /* directory */ - return IMGTOOLERR_UNIMPLEMENTED; - - default: - return IMGTOOLERR_UNEXPECTED; - } - - return IMGTOOLERR_SUCCESS; -} - - - -static void generic_prodos_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info) -{ - switch(state) - { - /* --- the following bits of info are returned as 64-bit signed integers --- */ - case IMGTOOLINFO_INT_INITIAL_PATH_SEPARATOR: info->i = 1; break; - case IMGTOOLINFO_INT_OPEN_IS_STRICT: info->i = 1; break; - case IMGTOOLINFO_INT_SUPPORTS_CREATION_TIME: info->i = 1; break; - case IMGTOOLINFO_INT_SUPPORTS_LASTMODIFIED_TIME: info->i = 1; break; - case IMGTOOLINFO_INT_WRITING_UNTESTED: info->i = 1; break; - case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES: info->i = sizeof(prodos_diskinfo); break; - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(prodos_direnum); break; - case IMGTOOLINFO_INT_PATH_SEPARATOR: info->i = '/'; break; - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "ProDOS format"); break; - case IMGTOOLINFO_STR_FILE: strcpy(info->s = imgtool_temp_str(), __FILE__); break; - case IMGTOOLINFO_STR_EOLN: strcpy(info->s = imgtool_temp_str(), "\r"); 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_BEGIN_ENUM: info->begin_enum = prodos_diskimage_beginenum; break; - case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = prodos_diskimage_nextenum; break; - case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = prodos_diskimage_freespace; break; - case IMGTOOLINFO_PTR_READ_FILE: info->read_file = prodos_diskimage_readfile; break; - case IMGTOOLINFO_PTR_WRITE_FILE: info->write_file = prodos_diskimage_writefile; break; - case IMGTOOLINFO_PTR_DELETE_FILE: info->delete_file = prodos_diskimage_deletefile; break; - case IMGTOOLINFO_PTR_LIST_FORKS: info->list_forks = prodos_diskimage_listforks; break; - case IMGTOOLINFO_PTR_CREATE_DIR: info->create_dir = prodos_diskimage_createdir; break; - case IMGTOOLINFO_PTR_DELETE_DIR: info->delete_dir = prodos_diskimage_deletedir; break; - case IMGTOOLINFO_PTR_GET_ATTRS: info->get_attrs = prodos_diskimage_getattrs; break; - case IMGTOOLINFO_PTR_SET_ATTRS: info->set_attrs = prodos_diskimage_setattrs; break; - case IMGTOOLINFO_PTR_SUGGEST_TRANSFER: info->suggest_transfer = prodos_diskimage_suggesttransfer; break; - case IMGTOOLINFO_PTR_GET_CHAIN: info->get_chain = prodos_diskimage_getchain; break; - } -} - - - -void prodos_525_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info) -{ - switch(state) - { - /* --- the following bits of info are returned as NULL-terminated strings --- */ - case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "prodos_525"); break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case IMGTOOLINFO_PTR_FLOPPY_CREATE: info->create = prodos_diskimage_create_525; break; - case IMGTOOLINFO_PTR_FLOPPY_OPEN: info->open = prodos_diskimage_open_525; break; - case IMGTOOLINFO_PTR_FLOPPY_FORMAT: info->p = (void *) floppyoptions_apple2; break; - - default: generic_prodos_get_info(imgclass, state, info); break; - } -} - - - -void prodos_35_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info) -{ - switch(state) - { - /* --- the following bits of info are returned as NULL-terminated strings --- */ - case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "prodos_35"); break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case IMGTOOLINFO_PTR_FLOPPY_CREATE: info->create = prodos_diskimage_create_35; break; - case IMGTOOLINFO_PTR_FLOPPY_OPEN: info->open = prodos_diskimage_open_35; break; - case IMGTOOLINFO_PTR_FLOPPY_FORMAT: info->p = (void *) floppyoptions_apple35_iigs; break; - - default: generic_prodos_get_info(imgclass, state, info); break; - } -} diff --git a/src/tools/imgtool/modules/psion.cpp b/src/tools/imgtool/modules/psion.cpp index 5759673349e..dba1130ddab 100644 --- a/src/tools/imgtool/modules/psion.cpp +++ b/src/tools/imgtool/modules/psion.cpp @@ -24,6 +24,11 @@ #include "imgtool.h" +#include "multibyte.h" +#include "opresolv.h" + +#include <cstdio> + #define MAXFILES 256 struct psion_file @@ -54,24 +59,23 @@ static psion_pack *get_psion_pack(imgtool::image &image) return (psion_pack*)image.extra_bytes(); } -uint16_t head_checksum(uint8_t* data) +uint16_t head_checksum(const uint8_t* data) { uint16_t checksum = 0; for (int i=0; i<6; i+=2) - checksum += (data[i]<<8 | data[i+1]); + checksum += get_u16be(&data[i]); return checksum; } uint16_t get_long_rec_size(imgtool::stream &stream) { - uint8_t size_h, size_l; + uint8_t size[2]; - stream.read(&size_h, 1); - stream.read(&size_l, 1); + stream.read(size, 2); - return (size_h<<8) | size_l; + return get_u16be(size); } uint32_t update_pack_index(psion_pack *pack) @@ -245,6 +249,7 @@ char *stream_getline(imgtool::stream &source, uint16_t max_len) source.read(&data, 1); if (data != '\n') source.seek(-1, SEEK_CUR); + [[fallthrough]]; case '\n': return line; default: @@ -483,7 +488,7 @@ static imgtoolerr_t datapack_next_enum(imgtool::directory &enumeration, imgtool_ return IMGTOOLERR_SUCCESS; } memcpy(ent.filename, pack->pack_index[iter->index].filename, 8); - sprintf(ent.attr, "Type: %02x ID: %02x", pack->pack_index[iter->index].type, pack->pack_index[iter->index].id); + snprintf(ent.attr, std::size(ent.attr), "Type: %02x ID: %02x", pack->pack_index[iter->index].type, pack->pack_index[iter->index].id); if (pack->pack_index[iter->index].data_rec) { diff --git a/src/tools/imgtool/modules/rsdos.cpp b/src/tools/imgtool/modules/rsdos.cpp index 4bcde9444ab..b4924338309 100644 --- a/src/tools/imgtool/modules/rsdos.cpp +++ b/src/tools/imgtool/modules/rsdos.cpp @@ -8,13 +8,18 @@ ****************************************************************************/ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> #include "imgtool.h" -#include "formats/coco_dsk.h" +#include "filter.h" #include "iflopimg.h" +#include "formats/coco_dsk.h" +#include "corestr.h" +#include "opresolv.h" + +#include <cstdio> +#include <cstdlib> +#include <cstring> + /* this structure mirrors the structure of an RS-DOS directory entry on disk */ struct rsdos_dirent { @@ -103,7 +108,7 @@ static imgtoolerr_t lookup_rsdos_file(imgtool::image &f, const char *fname, rsdo if (ent.filename[0] != -1) fnamebuf = get_dirent_fname(ent); } - while((ent.filename[0] != -1) && core_stricmp(fnamebuf.c_str(), fname)); + while((ent.filename[0] != -1) && core_stricmp(fnamebuf, fname)); if (ent.filename[0] == -1) return IMGTOOLERR_FILENOTFOUND; @@ -320,7 +325,7 @@ eof: } else { - /* Not the end of file */ + /* Note the end of file */ err = process_rsdos_file(&rsent, image, nullptr, filesize); if (err) return err; @@ -340,8 +345,8 @@ eof: std::string fname = get_dirent_fname(rsent); - snprintf(ent.filename, ARRAY_LENGTH(ent.filename), "%s", fname.c_str()); - snprintf(ent.attr, ARRAY_LENGTH(ent.attr), "%d %c", (int) rsent.ftype, (char) (rsent.asciiflag + 'B')); + snprintf(ent.filename, std::size(ent.filename), "%s", fname.c_str()); + snprintf(ent.attr, std::size(ent.attr), "%d %c", (int) rsent.ftype, (char) (rsent.asciiflag + 'B')); } return IMGTOOLERR_SUCCESS; } @@ -568,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()); @@ -584,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; } @@ -640,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/rt11.cpp b/src/tools/imgtool/modules/rt11.cpp index 01ab8741dd6..cc425adbdb6 100644 --- a/src/tools/imgtool/modules/rt11.cpp +++ b/src/tools/imgtool/modules/rt11.cpp @@ -72,12 +72,13 @@ ****************************************************************************/ #include "imgtool.h" -#include "formats/imageutl.h" #include "iflopimg.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> +#include "multibyte.h" + +#include <cstdio> +#include <cstdlib> +#include <cstring> namespace @@ -384,17 +385,17 @@ static imgtoolerr_t rt11_image_open(imgtool::image &image, imgtool::stream::ptr if (err) return err; - di->directory_start = pick_integer_le(buffer, 0724, 2); + di->directory_start = get_u16le(&buffer[0724]); // real-world images seem to never have a valid checksum, but directory_start is always 6 #if 0 uint16_t tmp, cksum; tmp = 0; - cksum = pick_integer_le(buffer, 0776, 2); + cksum = get_u16le(&buffer[0776]); for (int i = 0; i < 510; i+=2) { - tmp += pick_integer_le(buffer, i, 2); + tmp += get_u16le(&buffer[i]); } /* sanity check these values */ @@ -414,9 +415,9 @@ static imgtoolerr_t rt11_image_open(imgtool::image &image, imgtool::stream::ptr if (err) return err; - di->total_segments = pick_integer_le(buffer, 0, 2); - di->last_segment = pick_integer_le(buffer, 4, 2); - di->dirent_size = (pick_integer_le(buffer, 6, 2) + 7) * 2; + di->total_segments = get_u16le(&buffer[0]); + di->last_segment = get_u16le(&buffer[4]); + di->dirent_size = (get_u16le(&buffer[6]) + 7) * 2; di->dirents_per_block = (2 * BLOCK_SIZE - 10) / di->dirent_size; return IMGTOOLERR_SUCCESS; @@ -465,7 +466,7 @@ static imgtoolerr_t rt11_enum_seek(imgtool::image &image, return err; memcpy(&rt11enum->segment_data[BLOCK_SIZE], buffer, sizeof(buffer)); - rt11enum->data = pick_integer_le(rt11enum->segment_data, 8, 2); + rt11enum->data = get_u16le(&rt11enum->segment_data[8]); } rt11enum->segment = segment; } @@ -490,19 +491,19 @@ static imgtoolerr_t rt11_get_next_dirent(imgtool::image &image, /* populate the resulting dirent */ offset = (rt11enum->index * di->dirent_size) + 10; - rt_ent.status = pick_integer_le(rt11enum->segment_data, offset, 2); + rt_ent.status = get_u16le(&rt11enum->segment_data[offset]); memcpy(rt_ent.filename, &rt11enum->segment_data[offset + 2], 6); - rt_ent.filesize = pick_integer_le(rt11enum->segment_data, offset + 8, 2) * BLOCK_SIZE; + rt_ent.filesize = get_u16le(&rt11enum->segment_data[offset + 8]) * BLOCK_SIZE; rt_ent.data = rt11enum->data; - rt_ent.time = pick_integer_le(rt11enum->segment_data, offset + 12, 2); - rt11enum->data += pick_integer_le(rt11enum->segment_data, offset + 8, 2); + rt_ent.time = get_u16le(&rt11enum->segment_data[offset + 12]); + rt11enum->data += get_u16le(&rt11enum->segment_data[offset + 8]); /* identify next entry */ next_segment = rt11enum->segment; next_index = rt11enum->index + 1; if (next_index >= di->dirents_per_block || (rt_ent.status & E_EOS)) { - next_segment = pick_integer_le(rt11enum->segment_data, 2, 2); + next_segment = get_u16le(&rt11enum->segment_data[2]); next_index = 0; } diff --git a/src/tools/imgtool/modules/thomson.cpp b/src/tools/imgtool/modules/thomson.cpp index f122bc00520..1978e3720ba 100644 --- a/src/tools/imgtool/modules/thomson.cpp +++ b/src/tools/imgtool/modules/thomson.cpp @@ -112,10 +112,15 @@ */ #include "imgtool.h" +#include "filter.h" #include "iflopimg.h" -#include "formats/imageutl.h" -#include <time.h> +#include "corestr.h" +#include "multibyte.h" +#include "opresolv.h" + +#include <cstdio> +#include <ctime> #define MAXSIZE 80*16*256*2 /* room for two faces, double-density, 80 tracks */ @@ -590,14 +595,14 @@ static int thom_find_dirent(thom_floppy* f, unsigned head, { int n = 0; while ( 1 ) { - thom_get_dirent( f, head, n, d ); - if ( d->type == THOM_DIRENT_END ) return 0; - if ( d->type == THOM_DIRENT_FILE ) { - char buf[13]; - sprintf( buf, "%s.%s", d->name, d->ext ); - if ( ! strcmp( buf, name ) ) return 1; - } - n++; + thom_get_dirent( f, head, n, d ); + if ( d->type == THOM_DIRENT_END ) return 0; + if ( d->type == THOM_DIRENT_FILE ) { + char buf[13]; + snprintf( buf, std::size(buf), "%s.%s", d->name, d->ext ); + if ( ! strcmp( buf, name ) ) return 1; + } + n++; } } @@ -952,7 +957,7 @@ static imgtoolerr_t thom_read_file(imgtool::partition &part, /* convert filename */ thom_conv_filename( filename, name, ext ); - sprintf( fname, "%s.%s", name, ext ); + snprintf( fname, std::size(fname), "%s.%s", name, ext ); if ( ! thom_find_dirent( f, head, fname, &d ) ) return IMGTOOLERR_FILENOTFOUND; @@ -973,7 +978,7 @@ static imgtoolerr_t thom_delete_file(imgtool::partition &part, /* convert filename */ thom_conv_filename( filename, name, ext ); - sprintf( fname, "%s.%s", name, ext ); + snprintf( fname, std::size(fname), "%s.%s", name, ext ); if ( ! thom_find_dirent( f, head, fname, &d ) ) return IMGTOOLERR_FILENOTFOUND; @@ -1002,7 +1007,7 @@ static imgtoolerr_t thom_write_file(imgtool::partition &part, /* convert filename */ thom_conv_filename( filename, name, ext ); - sprintf( fname, "%s.%s", name, ext ); + snprintf( fname, std::size(fname), "%s.%s", name, ext ); /* check available space & find dir entry */ if ( thom_find_dirent( f, head, fname, &d ) ) { @@ -1067,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()); @@ -1081,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; @@ -1206,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", "@", @@ -1224,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 */ @@ -1368,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: @@ -1596,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))) { @@ -1740,7 +1744,7 @@ static imgtoolerr_t thom_basic_write_file(imgtool::partition &partition, if ((c == '\r') || (c == '\n')) break; - if (pos <= ARRAY_LENGTH(buf) - 1) + if (pos <= std::size(buf) - 1) { buf[pos++] = c; } @@ -1765,8 +1769,8 @@ static imgtoolerr_t thom_basic_write_file(imgtool::partition &partition, /* set up line header */ memset(&line_header, 0, sizeof(line_header)); /* linelength or offset (2-bytes) will be rewritten */ - place_integer_be(line_header, 0, 2, 0xffff); - place_integer_be(line_header, 2, 2, line_number); + put_u16be(&line_header[0], 0xffff); + put_u16be(&line_header[2], line_number); /* emit line header */ line_header_loc = mem_stream->tell(); @@ -1841,7 +1845,7 @@ static imgtoolerr_t thom_basic_write_file(imgtool::partition &partition, /* rewrite the line length */ end_line_loc = mem_stream->tell(); mem_stream->seek(line_header_loc, SEEK_SET); - place_integer_be(line_header, 0, 2, end_line_loc - line_header_loc); + put_u16be(&line_header[0], end_line_loc - line_header_loc); mem_stream->write(line_header, sizeof(line_header)); mem_stream->seek(end_line_loc, SEEK_SET); } @@ -1854,8 +1858,8 @@ static imgtoolerr_t thom_basic_write_file(imgtool::partition &partition, mem_stream->seek(0, SEEK_SET); /* Write file header */ - place_integer_be(file_header, 0, 1, 0xFF); - place_integer_be(file_header, 1, 2, mem_stream->size()); + file_header[0] = 0xFF; + put_u16be(&file_header[1], mem_stream->size()); mem_stream->write(file_header, 3); mem_stream->seek(0, SEEK_SET); @@ -1870,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; \ } \ } @@ -1941,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; } } @@ -2001,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 ); } } @@ -2025,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 ); } } @@ -2049,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/ti99.cpp b/src/tools/imgtool/modules/ti99.cpp index 04881c7b5ef..3f57f91db7c 100644 --- a/src/tools/imgtool/modules/ti99.cpp +++ b/src/tools/imgtool/modules/ti99.cpp @@ -18,15 +18,18 @@ - check allocation bitmap against corruption when an image is opened */ -#include <limits.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <time.h> #include "imgtool.h" #include "harddisk.h" #include "imghd.h" +#include "opresolv.h" + +#include <climits> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <ctime> + /* Concepts shared by both disk structures: ---------------------------------------- @@ -166,7 +169,7 @@ The DSK disk structure is used for floppy disks, and a few RAMDISKs as well. It supports 1600 AUs and 16 MBytes at most (the 16 MByte value is a - theorical maximum, as I doubt anyone has ever created so big a DSK volume). + theoretical maximum, as I doubt anyone has ever created so big a DSK volume). The disk sector size is always 256 bytes (the only potential exceptions are the SCSI floppy disk units and the TI-99 simulator on TI-990, but I don't @@ -524,7 +527,7 @@ struct dsk_vib /* the allocation unit associated with that */ /* bit has been allocated. */ /* Bits corresponding to system reserved AUs, */ - /* non-existant AUs, and bad AUs, are set to one, too. */ + /* non-existent AUs, and bad AUs, are set to one, too. */ /* (AU 0 is associated to LSBit of byte 0, */ /* AU 7 to MSBit of byte 0, AU 8 to LSBit */ /* of byte 1, etc.) */ @@ -976,17 +979,15 @@ static imgtoolerr_t open_image_lvl1(imgtool::stream::ptr &&file_handle, ti99_img if (img_format == if_harddisk) { - const hard_disk_info *info; - err = imghd_open(*file_handle, &l1_img->harddisk_handle); if (err) return err; - info = imghd_get_header(&l1_img->harddisk_handle); - l1_img->geometry.cylinders = info->cylinders; - l1_img->geometry.heads = info->heads; - l1_img->geometry.secspertrack = info->sectors; - if (info->sectorbytes != 256) + const auto &info = imghd_get_header(&l1_img->harddisk_handle); + l1_img->geometry.cylinders = info.cylinders; + l1_img->geometry.heads = info.heads; + l1_img->geometry.secspertrack = info.sectors; + if (info.sectorbytes != 256) { imghd_close(&l1_img->harddisk_handle); return IMGTOOLERR_CORRUPTIMAGE; /* TODO: support 512-byte sectors */ @@ -1300,15 +1301,13 @@ static void dsk_aphysrec_to_sector_address(int aphysrec, const ti99_geometry *ge geometry (I): disk image geometry address (O): physical sector address */ -#ifdef UNUSED_FUNCTION -static void win_aphysrec_to_sector_address(int aphysrec, const ti99_geometry *geometry, ti99_sector_address *address) +[[maybe_unused]] static void win_aphysrec_to_sector_address(int aphysrec, const ti99_geometry &geometry, ti99_sector_address &address) { - address.sector = aphysrec % l1_img->geometry.secspertrack; - aphysrec /= l1_img->geometry.secspertrack; - address.side = aphysrec % l1_img->geometry.heads; - address.cylinder = aphysrec / l1_img->geometry.heads; + address.sector = aphysrec % geometry.secspertrack; + aphysrec /= geometry.secspertrack; + address.side = aphysrec % geometry.heads; + address.cylinder = aphysrec / geometry.heads; } -#endif /* Read one 256-byte physical record from a disk image @@ -1327,7 +1326,7 @@ static int read_absolute_physrec(ti99_lvl1_imgref *l1_img, unsigned aphysrec, vo if (l1_img->img_format == if_harddisk) { #if 0 - win_aphysrec_to_sector_address(aphysrec, & l1_img->geometry, & address); + win_aphysrec_to_sector_address(aphysrec, l1_img->geometry, address); return read_sector(l1_img, & address, dest); #endif @@ -1563,7 +1562,7 @@ struct dsk_fdr UINT16BE xreclen; /* extended record len: if record len is >= 256, */ /* reclen is set to 0 and the actual reclen is */ /* stored here (Myarc HFDC only). TI reserved */ - /* this field for data chain pointer extension, */ + /* this field for data chain pointer extension, */ /* but this was never implemented. */ uint8_t flags; /* file status flags (see enum above) */ uint8_t recsperphysrec; /* logical records per physrec */ @@ -1579,9 +1578,9 @@ struct dsk_fdr /* implementation is regarded as a bug because */ /* program files do not define the fixrecs field */ /* field, so program field saved by the HFDC */ - /* DSR may be larger whan they should. */ + /* DSR may be larger than they should. */ uint8_t eof; /* EOF offset in last physrec for variable length */ - /* record files and program files (0->256)*/ + /* record files and program files (0->256) */ uint8_t reclen; /* logical record size in bytes ([1,255] 0->256) */ /* Maximum allowable record size for variable */ /* length record files. Reserved for program */ @@ -1625,7 +1624,7 @@ struct win_fdr /* implementation is regarded as a bug because */ /* program files do not define the fixrecs field */ /* field, so program field saved by the HFDC */ - /* DSR may be larger whan they should. */ + /* DSR may be larger than they should. */ /* other sibling FDRs: index of the first file */ /* physrec in this particular sibling FDR */ uint8_t eof; /* EOF offset in last physrec for variable length */ @@ -1837,7 +1836,7 @@ static int dsk_read_catalog(struct ti99_lvl2_imgref *l2_img, int aphysrec, ti99_ || ((dest->files[i].fdr_ptr && dest->files[i+1].fdr_ptr) && (memcmp(dest->files[i].name, dest->files[i+1].name, 10) >= 0))) { /* if the catalog is not sorted, we repair it */ - qsort(dest->files, ARRAY_LENGTH(dest->files), sizeof(dest->files[0]), + qsort(dest->files, std::size(dest->files), sizeof(dest->files[0]), cat_file_compare_qsort); break; } @@ -3304,8 +3303,7 @@ static int write_file_physrec(struct ti99_lvl2_fileref *l2_file, unsigned fphysr /* Write a field in every fdr record associated to a file */ -#ifdef UNUSED_FUNCTION -static int set_win_fdr_field(struct ti99_lvl2_fileref *l2_file, size_t offset, size_t size, void *data) +[[maybe_unused]] static int set_win_fdr_field(struct ti99_lvl2_fileref *l2_file, size_t offset, size_t size, void *data) { win_fdr fdr_buf; unsigned fdr_aphysrec; @@ -3313,7 +3311,7 @@ static int set_win_fdr_field(struct ti99_lvl2_fileref *l2_file, size_t offset, s for (fdr_aphysrec = l2_file->win.eldestfdr_aphysrec; fdr_aphysrec && ((errorcode = (read_absolute_physrec(&l2_file->win.l2_img->l1_img, fdr_aphysrec, &fdr_buf) ? IMGTOOLERR_READERROR : 0)) == 0); - fdr_aphysrec = get_win_fdr_nextsibFDR_physrec(l2_file->win.l2_img, &fdr_buf)) + fdr_aphysrec = get_win_fdr_nextsibFDR_aphysrec(l2_file->win.l2_img, &fdr_buf)) { memcpy(((uint8_t *) &fdr_buf) + offset, data, size); if (write_absolute_physrec(&l2_file->win.l2_img->l1_img, fdr_aphysrec, &fdr_buf)) @@ -3325,7 +3323,6 @@ static int set_win_fdr_field(struct ti99_lvl2_fileref *l2_file, size_t offset, s return errorcode; } -#endif static uint8_t get_file_flags(struct ti99_lvl2_fileref *l2_file) { @@ -3675,11 +3672,10 @@ static void set_file_update_date(struct ti99_lvl2_fileref *l2_file, ti99_date_ti } } -#ifdef UNUSED_FUNCTION -static void current_date_time(ti99_date_time *reply) +[[maybe_unused]] static void current_date_time(ti99_date_time *reply) { /* All these functions should be ANSI */ - time_t cur_time = time(NULL); + time_t cur_time = time(nullptr); struct tm expanded_time = *localtime(& cur_time); reply->time_MSB = (expanded_time.tm_hour << 3) | (expanded_time.tm_min >> 3); @@ -3687,7 +3683,6 @@ static void current_date_time(ti99_date_time *reply) reply->date_MSB = ((expanded_time.tm_year % 100) << 1) | ((expanded_time.tm_mon+1) >> 3); reply->date_LSB = ((expanded_time.tm_mon+1) << 5) | expanded_time.tm_mday; } -#endif #if 0 #pragma mark - @@ -3712,14 +3707,13 @@ struct ti99_lvl3_fileref int cur_pos_in_phys_rec; }; -#ifdef UNUSED_FUNCTION /* Open a file on level 3. To open a file on level 3, you must open (or create) the file on level 2, then pass the file reference to open_file_lvl3. */ -static int open_file_lvl3(ti99_lvl3_fileref *l3_file) +[[maybe_unused]] static int open_file_lvl3(ti99_lvl3_fileref *l3_file) { l3_file->cur_log_rec = 0; l3_file->cur_phys_rec = 0; @@ -3754,7 +3748,7 @@ static int is_eof(ti99_lvl3_fileref *l3_file) /* Read next record from a file */ -static int read_next_record(ti99_lvl3_fileref *l3_file, void *dest, int *out_reclen) +[[maybe_unused]] static int read_next_record(ti99_lvl3_fileref *l3_file, void *dest, int *out_reclen) { int errorcode; uint8_t physrec_buf[256]; @@ -3824,7 +3818,6 @@ static int read_next_record(ti99_lvl3_fileref *l3_file, void *dest, int *out_rec return 0; } -#endif #if 0 #pragma mark - @@ -4275,10 +4268,10 @@ static imgtoolerr_t dsk_image_nextenum(imgtool::directory &enumeration, imgtool_ { if (iter->listing_subdirs) { - fname_to_str(ent.filename, iter->image->dsk.catalogs[0].subdirs[iter->index[iter->level]].name, ARRAY_LENGTH(ent.filename)); + fname_to_str(ent.filename, iter->image->dsk.catalogs[0].subdirs[iter->index[iter->level]].name, std::size(ent.filename)); /* set type of DIR */ - snprintf(ent.attr, ARRAY_LENGTH(ent.attr), "DIR"); + snprintf(ent.attr, std::size(ent.attr), "DIR"); /* len in physrecs */ /* @BN@ return length in bytes */ @@ -4299,7 +4292,7 @@ static imgtoolerr_t dsk_image_nextenum(imgtool::directory &enumeration, imgtool_ if (reply) return IMGTOOLERR_READERROR; #if 0 - fname_to_str(ent.filename, fdr.name, ARRAY_LENGTH(ent.filename)); + fname_to_str(ent.filename, fdr.name, std::size(ent.filename)); #else { char buf[11]; @@ -4307,19 +4300,19 @@ static imgtoolerr_t dsk_image_nextenum(imgtool::directory &enumeration, imgtool_ ent.filename[0] = '\0'; if (iter->level) { - fname_to_str(ent.filename, iter->image->dsk.catalogs[0].subdirs[iter->index[0]].name, ARRAY_LENGTH(ent.filename)); - strncat(ent.filename, ".", ARRAY_LENGTH(ent.filename) - 1); + fname_to_str(ent.filename, iter->image->dsk.catalogs[0].subdirs[iter->index[0]].name, std::size(ent.filename)); + strncat(ent.filename, ".", std::size(ent.filename) - 1); } fname_to_str(buf, fdr.name, 11); - strncat(ent.filename, buf, ARRAY_LENGTH(ent.filename) - 1); + strncat(ent.filename, buf, std::size(ent.filename) - 1); } #endif /* parse flags */ if (fdr.flags & fdr99_f_program) - snprintf(ent.attr, ARRAY_LENGTH(ent.attr), "PGM%s", + snprintf(ent.attr, std::size(ent.attr), "PGM%s", (fdr.flags & fdr99_f_wp) ? " R/O" : ""); else - snprintf(ent.attr, ARRAY_LENGTH(ent.attr), "%c/%c %d%s", + snprintf(ent.attr, std::size(ent.attr), "%c/%c %d%s", (fdr.flags & fdr99_f_int) ? 'I' : 'D', (fdr.flags & fdr99_f_var) ? 'V' : 'F', fdr.reclen, @@ -4399,7 +4392,7 @@ static imgtoolerr_t win_image_nextenum(imgtool::directory &enumeration, imgtool_ if (iter->listing_subdirs) { #if 0 - fname_to_str(ent.filename, iter->catalog[iter->level].subdirs[iter->index[iter->level]].name, ARRAY_LENGTH(ent.filename)); + fname_to_str(ent.filename, iter->catalog[iter->level].subdirs[iter->index[iter->level]].name, std::size(ent.filename)); #else { char buf[11]; @@ -4408,16 +4401,16 @@ static imgtoolerr_t win_image_nextenum(imgtool::directory &enumeration, imgtool_ for (i=0; i<iter->level; i++) { fname_to_str(buf, iter->catalog[i].subdirs[iter->index[i]].name, 11); - strncat(ent.filename, buf, ARRAY_LENGTH(ent.filename) - 1); - strncat(ent.filename, ".", ARRAY_LENGTH(ent.filename) - 1); + strncat(ent.filename, buf, std::size(ent.filename) - 1); + strncat(ent.filename, ".", std::size(ent.filename) - 1); } fname_to_str(buf, iter->catalog[iter->level].subdirs[iter->index[iter->level]].name, 11); - strncat(ent.filename, buf, ARRAY_LENGTH(ent.filename) - 1); + strncat(ent.filename, buf, std::size(ent.filename) - 1); } #endif /* set type of DIR */ - snprintf(ent.attr, ARRAY_LENGTH(ent.attr), "DIR"); + snprintf(ent.attr, std::size(ent.attr), "DIR"); /* len in physrecs */ /* @BN@ return length in bytes */ @@ -4442,7 +4435,7 @@ static imgtoolerr_t win_image_nextenum(imgtool::directory &enumeration, imgtool_ if (reply) return IMGTOOLERR_READERROR; #if 0 - fname_to_str(ent.filename, iter->catalog[iter->level].files[iter->index[iter->level]].name, ARRAY_LENGTH(ent.filename)); + fname_to_str(ent.filename, iter->catalog[iter->level].files[iter->index[iter->level]].name, std::size(ent.filename)); #else { char buf[11]; @@ -4451,19 +4444,19 @@ static imgtoolerr_t win_image_nextenum(imgtool::directory &enumeration, imgtool_ for (i=0; i<iter->level; i++) { fname_to_str(buf, iter->catalog[i].subdirs[iter->index[i]].name, 11); - strncat(ent.filename, buf, ARRAY_LENGTH(ent.filename) - 1); - strncat(ent.filename, ".", ARRAY_LENGTH(ent.filename) - 1); + strncat(ent.filename, buf, std::size(ent.filename) - 1); + strncat(ent.filename, ".", std::size(ent.filename) - 1); } fname_to_str(buf, iter->catalog[iter->level].files[iter->index[iter->level]].name, 11); - strncat(ent.filename, buf, ARRAY_LENGTH(ent.filename) - 1); + strncat(ent.filename, buf, std::size(ent.filename) - 1); } #endif /* parse flags */ if (fdr.flags & fdr99_f_program) - snprintf(ent.attr, ARRAY_LENGTH(ent.attr), "PGM%s", + snprintf(ent.attr, std::size(ent.attr), "PGM%s", (fdr.flags & fdr99_f_wp) ? " R/O" : ""); else - snprintf(ent.attr, ARRAY_LENGTH(ent.attr), "%c/%c %d%s", + snprintf(ent.attr, std::size(ent.attr), "%c/%c %d%s", (fdr.flags & fdr99_f_int) ? 'I' : 'D', (fdr.flags & fdr99_f_var) ? 'V' : 'F', fdr.reclen, @@ -4948,7 +4941,7 @@ static imgtoolerr_t dsk_image_deletefile(imgtool::partition &partition, const ch /* free data AUs */ // fphysrecs = - get_UINT16BE(fdr.fphysrecs); + get_UINT16BE(fdr.fphysrecs); i = 0; cluster_index = 0; @@ -5090,7 +5083,7 @@ static imgtoolerr_t win_image_deletefile(imgtool::partition &partition, const ch /* check integrity of FDR sibling chain, and go to last sibling */ /* note that as we check that the back chain is consistent with the forward chain, we will also detect any cycle in the sibling chain, so we do not - need to check against them explicitely */ + need to check against them explicitly */ { int pastendoflist_flag; unsigned prevfdr_aphysrec; diff --git a/src/tools/imgtool/modules/ti990hd.cpp b/src/tools/imgtool/modules/ti990hd.cpp index 8edaeaf3fb6..a78589ff5aa 100644 --- a/src/tools/imgtool/modules/ti990hd.cpp +++ b/src/tools/imgtool/modules/ti990hd.cpp @@ -8,12 +8,15 @@ Raphael Nabet, 2003 */ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <limits.h> #include "imgtool.h" +#include "opresolv.h" + +#include <climits> +#include <cstdio> +#include <cstdlib> +#include <cstring> + /* Max sector length is bytes. Generally 256, except for a few older disk units which use 288-byte-long sectors, and SCSI units which generally use standard 512-byte-long sectors. */ @@ -96,7 +99,7 @@ enum Track 1 Sector 0 through N-2: optional disk program image loader Track 1 Sector N-1: copy of Track 0 Sector 0 Track 1 Sector N: copy of Track 0 Sector 1 - Last cylinder has disagnostic information (reported as .S$DIAG) + Last cylinder has diagnostic information (reported as .S$DIAG) Remaining sectors are used for fdr and data. */ @@ -214,7 +217,7 @@ struct ti990_fdr UINT16BE hkc; /* hask key count: the number of file descriptor records that are present in the directory that hashed to this record number */ UINT16BE hkv; /* hask key value: the result of the hash algorithm for the file name actually covered in this record */ char fnm[8]; /* file name */ - uint8_t rsv[2]; /* reserved */ + uint8_t rsv[2]; /* reserved */ UINT16BE fl1; /* flags word 1 */ UINT16BE flg; /* flags word 2 */ UINT16BE prs; /* physical record size */ @@ -227,31 +230,31 @@ struct ti990_fdr UINT32BE eom; /* end of medium record number */ UINT32BE bkm; /* end of medium block number */ UINT16BE ofm; /* end of medium offset / */ - /* prelog number for KIF */ + /* prelog number for KIF */ UINT32BE fbq; /* free block queue head */ UINT16BE btr; /* B-tree roots block # */ UINT32BE ebq; /* empty block queue head */ UINT16BE kdr; /* key descriptions record # */ - uint8_t ud[6]; /* last update date */ - uint8_t cd[6]; /* creation date */ - uint8_t apb; /* ADU's per block */ - uint8_t bpa; /* blocks per ADU */ - UINT16BE mrs; /* minimumu KIF record size */ - uint8_t sat[64]; /* secondary allocation table: 16 2-word entries. The first word of an entry contains the size, in ADUs, of the secondary allocation. The second word contains the starting ADU of the allocation. */ + uint8_t ud[6]; /* last update date */ + uint8_t cd[6]; /* creation date */ + uint8_t apb; /* ADU's per block */ + uint8_t bpa; /* blocks per ADU */ + UINT16BE mrs; /* minimum KIF record size */ + uint8_t sat[64]; /* secondary allocation table: 16 2-word entries. The first word of an entry contains the size, in ADUs, of the secondary allocation. The second word contains the starting ADU of the allocation. */ /* bytes >86 to >100 are optional */ - uint8_t res[10]; /* reserved: seem to be actually meaningful (at least under DX10 3.6.x) */ + uint8_t res[10]; /* reserved: seem to be actually meaningful (at least under DX10 3.6.x) */ char uid[8]; /* user id of file creator */ UINT16BE psa; /* public security attribute */ ti990_ace ace[9]; /* 9 access control entries */ - uint8_t fil[2]; /* not used */ + uint8_t fil[2]; /* not used */ }; /* ADR record: variant of FDR for Aliases The fields marked here with *** are in the ADR template to maintain - compatability with the FDR template. + compatibility with the FDR template. */ struct ti990_adr { @@ -284,19 +287,19 @@ struct ti990_cdr UINT16BE fill00; /* reserved */ UINT16BE fill01; /* reserved */ UINT16BE fdf; /* flags (same as fdr.flg) */ - uint8_t flg; /* channel flzgs */ - uint8_t iid; /* owner task installed ID */ - uint8_t typ; /* default resource type */ - uint8_t tf; /* resource type flags */ + uint8_t flg; /* channel flzgs */ + uint8_t iid; /* owner task installed ID */ + uint8_t typ; /* default resource type */ + uint8_t tf; /* resource type flags */ UINT16BE mxl; /* maximum message length */ - uint8_t fill04[6]; /* reserved (and, no, I don't know where fill02 and fill03 have gone) */ + uint8_t fill04[6]; /* reserved (and, no, I don't know where fill02 and fill03 have gone) */ UINT16BE rna; /* record number of next CDR or ADR */ UINT16BE raf; /* record # of actual FDR */ - uint8_t fill05[110]; /* reserved */ + uint8_t fill05[110]; /* reserved */ char uid[8]; /* user ID of channel creator */ UINT16BE psa; /* public security attribute */ - uint8_t scg[94]; /* "SDT with 9 control groups" (whatever it means - and, no, 94 is not dividable by 9) */ - uint8_t fill06[8]; /* reserved */ + uint8_t scg[94]; /* "SDT with 9 control groups" (whatever it means - and, no, 94 is not dividable by 9) */ + uint8_t fill06[8]; /* reserved */ }; /* @@ -321,19 +324,18 @@ union directory_entry */ struct tifile_header { - char tifiles[8]; /* always '\7TIFILES' */ - uint8_t secsused_MSB; /* file length in sectors (big-endian) */ - uint8_t secsused_LSB; - uint8_t flags; /* see enum above */ - uint8_t recspersec; /* records per sector */ - uint8_t eof; /* current position of eof in last sector (0->255)*/ - uint8_t reclen; /* bytes per record ([1,255] 0->256) */ - uint8_t fixrecs_MSB; /* file length in records (big-endian) */ - uint8_t fixrecs_LSB; - uint8_t res[128-16]; /* reserved */ + char tifiles[8]; /* always '\7TIFILES' */ + uint8_t secsused_MSB; /* file length in sectors (big-endian) */ + uint8_t secsused_LSB; + uint8_t flags; /* see enum above */ + uint8_t recspersec; /* records per sector */ + uint8_t eof; /* current position of eof in last sector (0->255)*/ + uint8_t reclen; /* bytes per record ([1,255] 0->256) */ + uint8_t fixrecs_MSB; /* file length in records (big-endian) */ + uint8_t fixrecs_LSB; + uint8_t res[128-16]; /* reserved */ }; - /* catalog entry (used for in-memory catalog) */ @@ -398,11 +400,9 @@ static imgtoolerr_t ti990_image_beginenum(imgtool::directory &enumeration, const static imgtoolerr_t ti990_image_nextenum(imgtool::directory &enumeration, imgtool_dirent &ent); static void ti990_image_closeenum(imgtool::directory &enumeration); static imgtoolerr_t ti990_image_freespace(imgtool::partition &partition, uint64_t *size); -#ifdef UNUSED_FUNCTION -static imgtoolerr_t ti990_image_readfile(imgtool::partition &partition, const char *fpath, imgtool::stream *destf); -static imgtoolerr_t ti990_image_writefile(imgtool::partition &partition, const char *fpath, imgtool::stream *sourcef, util::option_resolution *writeoptions); -static imgtoolerr_t ti990_image_deletefile(imgtool::partition &partition, const char *fpath); -#endif +[[maybe_unused]] static imgtoolerr_t ti990_image_readfile(imgtool::partition &partition, const char *fpath, imgtool::stream *destf); +[[maybe_unused]] static imgtoolerr_t ti990_image_writefile(imgtool::partition &partition, const char *fpath, imgtool::stream *sourcef, util::option_resolution *writeoptions); +[[maybe_unused]] static imgtoolerr_t ti990_image_deletefile(imgtool::partition &partition, const char *fpath); static imgtoolerr_t ti990_image_create(imgtool::image &image, imgtool::stream::ptr &&stream, util::option_resolution *createoptions); enum @@ -452,11 +452,10 @@ void ti990_get_info(const imgtool_class *imgclass, uint32_t state, union imgtool } } -#ifdef UNUSED_FUNCTION /* Convert a C string to a 8-character file name (padded with spaces if necessary) */ -static void str_to_fname(char dst[8], const char *src) +[[maybe_unused]] static void str_to_fname(char dst[8], const char *src) { int i; @@ -478,7 +477,6 @@ static void str_to_fname(char dst[8], const char *src) i++; } } -#endif /* Convert a 8-character file name to a C string (removing trailing spaces if necessary) @@ -555,7 +553,6 @@ static int read_sector_physical_len(imgtool::stream &file_handle, const ti990_ph return 0; } -#ifdef UNUSED_FUNCTION /* Read one sector from a disk image @@ -564,11 +561,10 @@ static int read_sector_physical_len(imgtool::stream &file_handle, const ti990_ph geometry: disk geometry (sectors per track, tracks per side, sides) dest: pointer to a destination buffer of geometry->bytes_per_sector bytes */ -static int read_sector_physical(imgtool::stream *file_handle, const ti990_phys_sec_address *address, const ti990_geometry *geometry, void *dest) +[[maybe_unused]] static int read_sector_physical(imgtool::stream &file_handle, const ti990_phys_sec_address *address, const ti990_geometry *geometry, void *dest) { return read_sector_physical_len(file_handle, address, geometry, dest, geometry->bytes_per_sector); } -#endif /* Write one sector to a disk image @@ -606,7 +602,6 @@ static int write_sector_physical_len(imgtool::stream &file_handle, const ti990_p return 0; } -#ifdef UNUSED_FUNCTION /* Write one sector to a disk image @@ -615,11 +610,10 @@ static int write_sector_physical_len(imgtool::stream &file_handle, const ti990_p geometry: disk geometry (sectors per track, tracks per side, sides) dest: pointer to a source buffer of geometry->bytes_per_sector bytes */ -static int write_sector_physical(imgtool::stream *file_handle, const ti990_phys_sec_address *address, const ti990_geometry *geometry, const void *src) +[[maybe_unused]] static int write_sector_physical(imgtool::stream &file_handle, const ti990_phys_sec_address *address, const ti990_geometry *geometry, const void *src) { return write_sector_physical_len(file_handle, address, geometry, src, geometry->bytes_per_sector); } -#endif /* Convert logical sector address to physical sector address @@ -651,7 +645,6 @@ static int read_sector_logical_len(imgtool::stream &file_handle, int secnum, con return read_sector_physical_len(file_handle, &address, geometry, dest, len); } -#ifdef UNUSED_FUNCTION /* Read one sector from a disk image @@ -660,11 +653,10 @@ static int read_sector_logical_len(imgtool::stream &file_handle, int secnum, con geometry: disk geometry (sectors per track, tracks per side, sides) dest: pointer to a destination buffer of geometry->bytes_per_sector bytes */ -static int read_sector_logical(imgtool::stream *file_handle, int secnum, const ti990_geometry *geometry, void *dest) +[[maybe_unused]] static int read_sector_logical(imgtool::stream &file_handle, int secnum, const ti990_geometry *geometry, void *dest) { return read_sector_logical_len(file_handle, secnum, geometry, dest, geometry->bytes_per_sector); } -#endif /* Write one sector to a disk image @@ -703,7 +695,6 @@ static int write_sector_logical(imgtool::stream &file_handle, int secnum, const #pragma mark CATALOG FILE ROUTINES #endif -#ifdef UNUSED_FUNCTION /* Find the catalog entry and fdr record associated with a file name @@ -715,7 +706,7 @@ static int write_sector_logical(imgtool::stream &file_handle, int secnum, const out_parent_fdr_secnum: on output, sector offset of the fdr for the parent directory fdr (-1 if root) (may be NULL) */ -static int find_fdr(ti990_image *image, const char fpath[MAX_PATH_LEN+1], int *catalog_index, int *out_fdr_secnum, int *out_parent_fdr_secnum) +static imgtoolerr_t find_fdr(ti990_image *image, const char fpath[MAX_PATH_LEN+1], int *catalog_index, int *out_fdr_secnum, int *out_parent_fdr_secnum) { int fdr_secnum = -1, parent_fdr_secnum; int i; @@ -737,7 +728,7 @@ static int find_fdr(ti990_image *image, const char fpath[MAX_PATH_LEN+1], int *c do { /* read directory header */ - reply = read_sector_logical_len(image->file_handle, base, & image->geometry, &dor, sizeof(dor)); + reply = read_sector_logical_len(*image->file_handle, base, & image->geometry, &dor, sizeof(dor)); if (reply) return IMGTOOLERR_READERROR; @@ -765,7 +756,7 @@ static int find_fdr(ti990_image *image, const char fpath[MAX_PATH_LEN+1], int *c i = hash_key; while (1) { - reply = read_sector_logical_len(image->file_handle, base + i, & image->geometry, + reply = read_sector_logical_len(*image->file_handle, base + i, & image->geometry, & xdr, 0x86); if (reply) return IMGTOOLERR_READERROR; @@ -800,7 +791,7 @@ static int find_fdr(ti990_image *image, const char fpath[MAX_PATH_LEN+1], int *c if (flag & fdr_flg_ali) { /* read original fdr */ - reply = read_sector_logical_len(image->file_handle, base + get_UINT16BE(xdr.adr.raf), + reply = read_sector_logical_len(*image->file_handle, base + get_UINT16BE(xdr.adr.raf), & image->geometry, & xdr, 0x86); flag = get_UINT16BE(xdr.fdr.flg); @@ -835,9 +826,8 @@ static int find_fdr(ti990_image *image, const char fpath[MAX_PATH_LEN+1], int *c if (out_parent_fdr_secnum) *out_parent_fdr_secnum = parent_fdr_secnum; - return 0; + return IMGTOOLERR_SUCCESS; } -#endif #if 0 /* @@ -1251,7 +1241,7 @@ static imgtoolerr_t ti990_image_nextenum(imgtool::directory &enumeration, imgtoo else { #if 0 - fname_to_str(ent.filename, iter->xdr[iter->level].fdr.fnm, ARRAY_LENGTH(ent.filename)); + fname_to_str(ent.filename, iter->xdr[iter->level].fdr.fnm, std::size(ent.filename)); #else { int i; @@ -1261,11 +1251,11 @@ static imgtoolerr_t ti990_image_nextenum(imgtool::directory &enumeration, imgtoo for (i=0; i<iter->level; i++) { fname_to_str(buf, iter->xdr[i].fdr.fnm, 9); - strncat(ent.filename, buf, ARRAY_LENGTH(ent.filename) - 1); - strncat(ent.filename, ".", ARRAY_LENGTH(ent.filename) - 1); + strncat(ent.filename, buf, std::size(ent.filename) - 1); + strncat(ent.filename, ".", std::size(ent.filename) - 1); } fname_to_str(buf, iter->xdr[iter->level].fdr.fnm, 9); - strncat(ent.filename, buf, ARRAY_LENGTH(ent.filename) - 1); + strncat(ent.filename, buf, std::size(ent.filename) - 1); } #endif @@ -1273,7 +1263,7 @@ static imgtoolerr_t ti990_image_nextenum(imgtool::directory &enumeration, imgtoo flag = get_UINT16BE(iter->xdr[iter->level].fdr.flg); if (flag & fdr_flg_cdr) { - snprintf(ent.attr, ARRAY_LENGTH(ent.attr), "CHANNEL"); + snprintf(ent.attr, std::size(ent.attr), "CHANNEL"); ent.filesize = 0; } @@ -1291,7 +1281,7 @@ static imgtoolerr_t ti990_image_nextenum(imgtool::directory &enumeration, imgtoo fname_to_str(buf, target_fdr.fnm, 9); - snprintf(ent.attr, ARRAY_LENGTH(ent.attr), "ALIAS OF %s", buf); + snprintf(ent.attr, std::size(ent.attr), "ALIAS OF %s", buf); ent.filesize = 0; } @@ -1341,7 +1331,7 @@ static imgtoolerr_t ti990_image_nextenum(imgtool::directory &enumeration, imgtoo } break; } - snprintf(ent.attr, ARRAY_LENGTH(ent.attr), + snprintf(ent.attr, std::size(ent.attr), "%s %c %s%s%s%s%s", fmt, (flag & fdr_flg_all) ? 'N' : 'C', type, (flag & fdr_flg_blb) ? "" : " BLK", (flag & fdr_flg_tmp) ? " TMP" : "", @@ -1455,14 +1445,12 @@ static imgtoolerr_t ti990_image_freespace(imgtool::partition &partition, uint64_ return IMGTOOLERR_SUCCESS; } -#ifdef UNUSED_FUNCTION /* Extract a file from a ti990_image. */ static imgtoolerr_t ti990_image_readfile(imgtool::partition &partition, const char *fpath, imgtool::stream *destf) { - imgtool::image *img = &partition->image(); - ti990_image *image = get_ti990_image(img); + ti990_image *image = get_ti990_image(partition.image()); int catalog_index, fdr_secnum, parent_fdr_secnum; imgtoolerr_t reply; @@ -1473,7 +1461,7 @@ static imgtoolerr_t ti990_image_readfile(imgtool::partition &partition, const ch /* ... */ - return 0; + return IMGTOOLERR_SUCCESS; #if 0 ti99_image *image = (ti99_image*) img; @@ -1549,7 +1537,7 @@ static imgtoolerr_t ti990_image_readfile(imgtool::partition &partition, const ch lnks_index++; } - return 0; + return IMGTOOLERR_SUCCESS; #endif } @@ -1558,8 +1546,7 @@ static imgtoolerr_t ti990_image_readfile(imgtool::partition &partition, const ch */ static imgtoolerr_t ti990_image_writefile(imgtool::partition &partition, const char *fpath, imgtool::stream *sourcef, util::option_resolution *writeoptions) { - imgtool::image *img = &partition->image(); - ti990_image *image = get_ti990_image(img); + ti990_image *image = get_ti990_image(partition.image()); int catalog_index, fdr_secnum, parent_fdr_secnum; imgtoolerr_t reply; @@ -1571,7 +1558,7 @@ static imgtoolerr_t ti990_image_writefile(imgtool::partition &partition, const c /* ... */ - return 0; + return IMGTOOLERR_SUCCESS; #if 0 ti99_image *image = (ti99_image*) img; @@ -1673,7 +1660,7 @@ static imgtoolerr_t ti990_image_writefile(imgtool::partition &partition, const c if (write_sector_logical(image->file_handle, 0, & image->geometry, &image->sec0)) return IMGTOOLERR_WRITEERROR; - return 0; + return IMGTOOLERR_SUCCESS; #endif } @@ -1682,8 +1669,7 @@ static imgtoolerr_t ti990_image_writefile(imgtool::partition &partition, const c */ static imgtoolerr_t ti990_image_deletefile(imgtool::partition &partition, const char *fpath) { - imgtool::image *img = &partition->image(); - ti990_image *image = get_ti990_image(img); + ti990_image *image = get_ti990_image(partition.image()); int catalog_index, fdr_secnum, parent_fdr_secnum; imgtoolerr_t reply; @@ -1694,7 +1680,7 @@ static imgtoolerr_t ti990_image_deletefile(imgtool::partition &partition, const /* ... */ - return 0; + return IMGTOOLERR_SUCCESS; #if 0 ti99_image *image = (ti99_image*) img; @@ -1762,10 +1748,9 @@ static imgtoolerr_t ti990_image_deletefile(imgtool::partition &partition, const if (write_sector_logical(image->file_handle, 0, & image->geometry, &image->sec0)) return IMGTOOLERR_WRITEERROR; - return 0; + return IMGTOOLERR_SUCCESS; #endif } -#endif /* Create a blank ti990_image. diff --git a/src/tools/imgtool/modules/vzdos.cpp b/src/tools/imgtool/modules/vzdos.cpp index bf46863bb28..b7dee751434 100644 --- a/src/tools/imgtool/modules/vzdos.cpp +++ b/src/tools/imgtool/modules/vzdos.cpp @@ -1,4 +1,4 @@ -// license:GPL-2.0+ +// license:BSD-3-Clause // copyright-holders:Dirk Best /**************************************************************************** @@ -8,15 +8,23 @@ ****************************************************************************/ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <math.h> #include "imgtool.h" -#include "formats/imageutl.h" -#include "formats/vt_dsk.h" +#include "filter.h" #include "iflopimg.h" +#include "formats/vt_dsk_legacy.h" + +#include "corestr.h" +#include "hashing.h" +#include "multibyte.h" +#include "opresolv.h" + +#include <algorithm> +#include <cmath> +#include <cstdio> +#include <cstdlib> +#include <cstring> + /* sector format @@ -44,13 +52,22 @@ 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() : + start_track(0), start_sector(0), + start_address(0), end_address(0) + { + memset(&node, 0, sizeof(node)); + } }; struct vz_iterator @@ -80,18 +97,6 @@ static int vzdos_get_fname_len(const char *fname) return len; } -/* calculate checksum-16 of buffer */ -static uint16_t chksum16(uint8_t *buffer, int len) -{ - int i; - uint16_t sum = 0; - - for (i = 0; i < len; i++) - sum += buffer[i]; - - return sum; -} - /* returns the offset where the actual sector data starts */ static imgtoolerr_t vzdos_get_data_start(imgtool::image &img, int track, int sector, int *start) { @@ -127,7 +132,7 @@ static imgtoolerr_t vzdos_read_sector_data(imgtool::image &img, int track, int s if (ret) return (imgtoolerr_t)ret; /* verify sector checksums */ - if (pick_integer_le(buffer, DATA_SIZE + 2, 2) != chksum16(buffer, DATA_SIZE + 2)) + if (get_u16le(&buffer[DATA_SIZE + 2]) != util::sum16_creator::simple(buffer, DATA_SIZE + 2)) return IMGTOOLERR_CORRUPTFILE; memcpy(data, &buffer, DATA_SIZE + 2); @@ -145,7 +150,7 @@ static imgtoolerr_t vzdos_write_sector_data(imgtool::image &img, int track, int if (ret) return (imgtoolerr_t)ret; memcpy(buffer, data, DATA_SIZE + 2); - place_integer_le(buffer, DATA_SIZE + 2, 2, chksum16(data, DATA_SIZE + 2)); + put_u16le(&buffer[DATA_SIZE + 2], util::sum16_creator::simple(data, DATA_SIZE + 2)); ret = floppy_write_sector(imgtool_floppy(img), 0, track, sector_order[sector], data_start, buffer, sizeof(buffer), 0); /* TODO: pass ddam argument from imgtool */ if (ret) return (imgtoolerr_t)ret; @@ -157,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); } @@ -166,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); - ent->start_track = pick_integer_le(&buffer[entry], 10, 1); - ent->start_sector = pick_integer_le(&buffer[entry], 11, 1); - ent->start_address = pick_integer_le(&buffer[entry], 12, 2); - ent->end_address = pick_integer_le(&buffer[entry], 14, 2); + 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 */ @@ -206,10 +210,10 @@ static imgtoolerr_t vzdos_set_dirent(imgtool::image &img, int index, vzdos_diren entry = ((index % 8) * sizeof(vzdos_dirent)); memcpy(&buffer[entry], &ent, 10); - place_integer_le(buffer, entry + 10, 1, ent.start_track); - place_integer_le(buffer, entry + 11, 1, ent.start_sector); - place_integer_le(buffer, entry + 12, 2, ent.start_address); - place_integer_le(buffer, entry + 14, 2, ent.end_address); + buffer[entry + 10] = ent.start_track; + buffer[entry + 11] = ent.start_sector; + put_u16le(&buffer[entry + 12], ent.start_address); + put_u16le(&buffer[entry + 14], ent.end_address); /* save new sector */ ret = vzdos_write_sector_data(img, 0, (int) index / 8, buffer); @@ -221,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]; @@ -246,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) @@ -359,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] = { @@ -368,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; } @@ -424,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; @@ -445,7 +441,7 @@ static imgtoolerr_t vzdos_diskimage_nextenum(imgtool::directory &enumeration, im default: type = "Unknown"; } - snprintf(ent.attr, ARRAY_LENGTH(ent.attr), "%s", type); + snprintf(ent.attr, std::size(ent.attr), "%s", type); iter->index++; } @@ -500,12 +496,12 @@ static imgtoolerr_t vzdos_diskimage_readfile(imgtool::partition &partition, cons if (ret) return ret; /* detect sectors pointing to themselfs */ - if ((track == (int)pick_integer_le(buffer, DATA_SIZE, 1)) && (sector == (int)pick_integer_le(buffer, DATA_SIZE + 1, 1))) + if ((track == (int)buffer[DATA_SIZE]) && (sector == (int)buffer[DATA_SIZE + 1])) return IMGTOOLERR_CORRUPTIMAGE; /* load next track and sector values */ - track = pick_integer_le(buffer, DATA_SIZE, 1); - sector = pick_integer_le(buffer, DATA_SIZE + 1, 1); + track = buffer[DATA_SIZE]; + sector = buffer[DATA_SIZE + 1]; /* track 0 is invalid */ if ((track == 0) && (filesize > DATA_SIZE)) @@ -581,8 +577,8 @@ static imgtoolerr_t vzdos_diskimage_deletefile(imgtool::partition &partition, co if (ret) return ret; /* load next track and sector values */ - next_track = pick_integer_le(buffer, DATA_SIZE, 1); - next_sector = pick_integer_le(buffer, DATA_SIZE + 1, 1); + next_track = buffer[DATA_SIZE]; + next_sector = buffer[DATA_SIZE + 1]; /* overwrite sector with default values */ ret = vzdos_clear_sector(img, track, sector); @@ -617,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 */ @@ -702,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 */ @@ -711,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()); @@ -751,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"; } @@ -824,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; @@ -839,8 +830,8 @@ 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); - place_integer_le(header, 22, 2, entry.start_address); + 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 */ destf.write(header, sizeof(header)); @@ -863,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 = pick_integer_le(header, 22, 2); + 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 */ @@ -887,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) { @@ -936,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 9a29180c9da..f68f8b4eac6 100644 --- a/src/tools/imgtool/stream.cpp +++ b/src/tools/imgtool/stream.cpp @@ -8,20 +8,180 @@ ***************************************************************************/ -#include <stdio.h> -#include <string.h> -#include <zlib.h> +#include "stream.h" -#include "unzip.h" -#include "osdcore.h" #include "imgtool.h" +#include "corefile.h" +#include "ioprocs.h" +#include "path.h" +#include "unzip.h" + +#include <cassert> +#include <cstdarg> +#include <cstdio> +#include <cstring> +#include <tuple> + + + +namespace imgtool { + +namespace { + +class stream_read_wrapper : public virtual util::random_read +{ +public: + stream_read_wrapper(stream::ptr &&stream, std::uint8_t filler) noexcept + : m_stream(stream.release()) + , m_filler(filler) + , m_close(true) + { + assert(m_stream); + } + + stream_read_wrapper(stream &stream, std::uint8_t filler) noexcept + : m_stream(&stream) + , m_filler(filler) + , m_close(false) + { + } + + virtual ~stream_read_wrapper() + { + if (m_close) + delete m_stream; + } + + virtual std::error_condition seek(std::int64_t offset, int whence) noexcept override + { + m_stream->seek(offset, whence); + return std::error_condition(); + } + + virtual std::error_condition tell(std::uint64_t &result) noexcept override + { + result = m_stream->tell(); + return std::error_condition(); + } + + virtual std::error_condition length(std::uint64_t &result) noexcept override + { + result = m_stream->size(); + return std::error_condition(); + } + + virtual std::error_condition read_some(void *buffer, std::size_t length, std::size_t &actual) noexcept override + { + actual = m_stream->read(buffer, length); + if (actual < length) + std::memset(reinterpret_cast<std::uint8_t *>(buffer) + actual, m_filler, length - actual); + return std::error_condition(); + } + + virtual std::error_condition read_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); + actual = m_stream->read(buffer, length); + m_stream->seek(pos, SEEK_SET); + if (actual < length) + std::memset(reinterpret_cast<std::uint8_t *>(buffer) + actual, m_filler, length - actual); + return std::error_condition(); + } + +protected: + stream *const m_stream; + std::uint8_t m_filler; + bool const m_close; +}; + + +class stream_read_write_wrapper : public stream_read_wrapper, public util::random_read_write +{ +public: + using stream_read_wrapper::stream_read_wrapper; + + virtual std::error_condition finalize() noexcept override + { + return std::error_condition(); + } + + virtual std::error_condition flush() noexcept override + { + return std::error_condition(); + } + + virtual std::error_condition write_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(); + if (size < pos) + { + m_stream->seek(size, SEEK_SET); + size += m_stream->fill(m_filler, pos - size); + } + actual = (size >= pos) ? m_stream->write(buffer, length) : 0U; + return (actual == length) ? std::error_condition() : std::errc::io_error; + } + + virtual std::error_condition write_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(); + if (offset > size) + { + m_stream->seek(size, SEEK_SET); + size += m_stream->fill(m_filler, offset - size); + } + else + { + m_stream->seek(offset, SEEK_SET); + } + actual = (size >= offset) ? m_stream->write(buffer, length) : 0U; + m_stream->seek(pos, SEEK_SET); + return (actual == length) ? std::error_condition() : std::errc::io_error; + } +}; + +} // anonymous namespace + + +util::random_read::ptr stream_read(stream::ptr &&s, std::uint8_t filler) noexcept +{ + util::random_read::ptr result; + if (s) + result.reset(new (std::nothrow) stream_read_wrapper(std::move(s), filler)); + return result; +} + +util::random_read::ptr stream_read(stream &s, std::uint8_t filler) noexcept +{ + util::random_read::ptr result(new (std::nothrow) stream_read_wrapper(s, filler)); + return result; +} + +util::random_read_write::ptr stream_read_write(stream::ptr &&s, std::uint8_t filler) noexcept +{ + util::random_read_write::ptr result; + if (s) + result.reset(new (std::nothrow) stream_read_write_wrapper(std::move(s), filler)); + return result; +} + +util::random_read_write::ptr stream_read_write(stream &s, std::uint8_t filler) noexcept +{ + util::random_read_write::ptr result(new (std::nothrow) stream_read_write_wrapper(s, filler)); + return result; +} + + //------------------------------------------------- // ctor //------------------------------------------------- -imgtool::stream::stream(bool wp) +stream::stream(bool wp) : imgtype(IMG_FILE) , write_protect(wp) , position(0) @@ -36,14 +196,15 @@ imgtool::stream::stream(bool wp) // ctor //------------------------------------------------- -imgtool::stream::stream(bool wp, util::core_file::ptr &&f) +stream::stream(bool wp, util::core_file::ptr &&f) : imgtype(IMG_FILE) , write_protect(wp) , position(0) - , filesize(f->size()) + , filesize(0) , file(std::move(f)) , buffer(nullptr) { + file->length(filesize); // FIXME: check error return } @@ -51,7 +212,7 @@ imgtool::stream::stream(bool wp, util::core_file::ptr &&f) // ctor //------------------------------------------------- -imgtool::stream::stream(bool wp, std::size_t size) +stream::stream(bool wp, std::size_t size) : imgtype(IMG_MEM) , write_protect(wp) , position(0) @@ -66,7 +227,7 @@ imgtool::stream::stream(bool wp, std::size_t size) // ctor //------------------------------------------------- -imgtool::stream::stream(bool wp, std::size_t size, void *buf) +stream::stream(bool wp, std::size_t size, void *buf) : imgtype(IMG_MEM) , write_protect(wp) , position(0) @@ -81,7 +242,7 @@ imgtool::stream::stream(bool wp, std::size_t size, void *buf) // dtor //------------------------------------------------- -imgtool::stream::~stream() +stream::~stream() { if (buffer) free(buffer); @@ -92,39 +253,39 @@ imgtool::stream::~stream() // open_zip //------------------------------------------------- -imgtool::stream::ptr imgtool::stream::open_zip(const std::string &zipname, const char *subname, int read_or_write) +stream::ptr stream::open_zip(const std::string &zipname, const char *subname, int read_or_write) { if (read_or_write) - return imgtool::stream::ptr(); + return stream::ptr(); /* check to see if the file exists */ FILE *f = fopen(zipname.c_str(), "r"); if (!f) - return imgtool::stream::ptr(); + return stream::ptr(); fclose(f); - imgtool::stream::ptr imgfile(new imgtool::stream(true)); + stream::ptr imgfile(new stream(true)); imgfile->imgtype = IMG_MEM; util::archive_file::ptr z; util::archive_file::open_zip(zipname, z); if (!z) - return imgtool::stream::ptr(); + return stream::ptr(); int zipent = z->first_file(); while ((zipent >= 0) && subname && strcmp(subname, z->current_name().c_str())) zipent = z->next_file(); if (zipent < 0) - return imgtool::stream::ptr(); + return stream::ptr(); imgfile->filesize = z->current_uncompressed_length(); imgfile->buffer = reinterpret_cast<std::uint8_t *>(malloc(z->current_uncompressed_length())); if (!imgfile->buffer) - return imgtool::stream::ptr(); + return stream::ptr(); - if (z->decompress(imgfile->buffer, z->current_uncompressed_length()) != util::archive_file::error::NONE) - return imgtool::stream::ptr(); + if (z->decompress(imgfile->buffer, z->current_uncompressed_length())) + return stream::ptr(); return imgfile; } @@ -135,7 +296,7 @@ imgtool::stream::ptr imgtool::stream::open_zip(const std::string &zipname, const // open //------------------------------------------------- -imgtool::stream::ptr imgtool::stream::open(const std::string &filename, int read_or_write) +stream::ptr stream::open(const std::string &filename, int read_or_write) { static const uint32_t write_modes[] = { @@ -144,23 +305,22 @@ imgtool::stream::ptr imgtool::stream::open(const std::string &filename, int read OPEN_FLAG_READ | OPEN_FLAG_WRITE, OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE }; - imgtool::stream::ptr s; + stream::ptr s; char c; // maybe we are just a ZIP? - std::string ext = core_filename_extract_extension(filename); - if (!core_stricmp(ext.c_str(), ".zip")) + if (core_filename_ends_with(filename, ".zip")) return open_zip(filename, nullptr, read_or_write); util::core_file::ptr f = nullptr; auto const filerr = util::core_file::open(filename, write_modes[read_or_write], f); - if (filerr != osd_file::error::NONE) + if (filerr) { if (!read_or_write) { int const len = filename.size(); - /* can't open the file; try opening ZIP files with other names */ + // can't open the file; try opening ZIP files with other names std::vector<char> buf(len + 1); strcpy(&buf[0], filename.c_str()); @@ -179,11 +339,11 @@ imgtool::stream::ptr imgtool::stream::open(const std::string &filename, int read return s; } - /* ah well, it was worth a shot */ - return imgtool::stream::ptr(); + // ah well, it was worth a shot + return stream::ptr(); } - imgtool::stream::ptr imgfile(new imgtool::stream(read_or_write ? false : true, std::move(f))); + stream::ptr imgfile(new stream(read_or_write ? false : true, std::move(f))); // normal file return imgfile; @@ -194,11 +354,11 @@ imgtool::stream::ptr imgtool::stream::open(const std::string &filename, int read // open_write_stream //------------------------------------------------- -imgtool::stream::ptr imgtool::stream::open_write_stream(int size) +stream::ptr stream::open_write_stream(int size) { - imgtool::stream::ptr imgfile(new imgtool::stream(false, size)); + stream::ptr imgfile(new stream(false, size)); if (!imgfile->buffer) - return imgtool::stream::ptr(); + return stream::ptr(); return imgfile; } @@ -208,9 +368,9 @@ imgtool::stream::ptr imgtool::stream::open_write_stream(int size) // open_mem //------------------------------------------------- -imgtool::stream::ptr imgtool::stream::open_mem(void *buf, size_t sz) +stream::ptr stream::open_mem(void *buf, size_t sz) { - imgtool::stream::ptr imgfile(new imgtool::stream(false, sz, buf)); + stream::ptr imgfile(new stream(false, sz, buf)); return imgfile; } @@ -220,7 +380,7 @@ imgtool::stream::ptr imgtool::stream::open_mem(void *buf, size_t sz) // core_file //------------------------------------------------- -util::core_file *imgtool::stream::core_file() +util::core_file *stream::core_file() { return (imgtype == IMG_FILE) ? file.get() : nullptr; } @@ -230,22 +390,22 @@ util::core_file *imgtool::stream::core_file() // read //------------------------------------------------- -uint32_t imgtool::stream::read(void *buf, uint32_t sz) +uint32_t stream::read(void *buf, uint32_t sz) { - uint32_t result = 0; + std::error_condition err; + size_t result = 0; switch(imgtype) { case IMG_FILE: - assert(sz == (uint32_t) sz); - file->seek(position, SEEK_SET); - result = file->read(buf, (uint32_t) sz); + if (!file->seek(position, SEEK_SET)) + std::tie(err, result) = util::read(*file, buf, sz); // FIXME: check error return break; case IMG_MEM: - /* do we have to limit sz? */ + // do we have to limit sz? if (sz > (filesize - position)) - sz = (uint32_t) (filesize - position); + sz = uint32_t(filesize - position); memcpy(buf, buffer + position, sz); result = sz; @@ -264,31 +424,32 @@ uint32_t imgtool::stream::read(void *buf, uint32_t sz) // write //------------------------------------------------- -uint32_t imgtool::stream::write(const void *buf, uint32_t sz) +uint32_t stream::write(const void *buf, uint32_t sz) { - void *new_buffer; - uint32_t result = 0; + std::error_condition err; + size_t result = 0; switch(imgtype) { case IMG_MEM: if (!write_protect) { - /* do we have to expand the buffer? */ - if (filesize < position + sz) + // do we have to expand the buffer? + const uint64_t end = position + sz; + if ((filesize < end) && (size_t(end) == end)) { - /* try to expand the buffer */ - new_buffer = realloc(buffer , position + sz); + // try to expand the buffer + void *const new_buffer = realloc(buffer, size_t(end)); if (new_buffer) { - buffer = (uint8_t*)new_buffer; - filesize = position + sz; + buffer = reinterpret_cast<uint8_t *>(new_buffer); + filesize = end; } } - /* do we have to limit sz? */ + // do we have to limit sz? if (sz > (filesize - position)) - sz = (uint32_t) (filesize - position); + sz = uint32_t(filesize - position); memcpy(buffer + position, buf, sz); result = sz; @@ -296,8 +457,8 @@ uint32_t imgtool::stream::write(const void *buf, uint32_t sz) break; case IMG_FILE: - file->seek(position, SEEK_SET); - result = file->write(buf, sz); + if (!file->seek(position, SEEK_SET)) + std::tie(err, result) = util::write(*file, buf, sz); // FIXME: check error return break; default: @@ -305,10 +466,10 @@ uint32_t imgtool::stream::write(const void *buf, uint32_t sz) break; } - /* advance the file pointer */ + // advance the file pointer position += result; - /* did we grow the file */ + // did we grow the file if (position > filesize) filesize = position; return result; @@ -319,39 +480,17 @@ uint32_t imgtool::stream::write(const void *buf, uint32_t sz) // size //------------------------------------------------- -uint64_t imgtool::stream::size() const +uint64_t stream::size() const { return filesize; } //------------------------------------------------- -// getptr -//------------------------------------------------- - -void *imgtool::stream::getptr() -{ - void *ptr; - - switch(imgtype) - { - case IMG_MEM: - ptr = buffer; - break; - - default: - ptr = nullptr; - break; - } - return ptr; -} - - -//------------------------------------------------- // seek //------------------------------------------------- -int imgtool::stream::seek(int64_t pos, int where) +int stream::seek(int64_t pos, int where) { switch(where) { @@ -379,7 +518,7 @@ int imgtool::stream::seek(int64_t pos, int where) // tell //------------------------------------------------- -uint64_t imgtool::stream::tell() +uint64_t stream::tell() { return position; } @@ -389,7 +528,7 @@ uint64_t imgtool::stream::tell() // transfer //------------------------------------------------- -uint64_t imgtool::stream::transfer(imgtool::stream &dest, imgtool::stream &source, uint64_t sz) +uint64_t stream::transfer(stream &dest, stream &source, uint64_t sz) { uint64_t result = 0; uint64_t readsz; @@ -409,69 +548,17 @@ uint64_t imgtool::stream::transfer(imgtool::stream &dest, imgtool::stream &sourc // transfer_all //------------------------------------------------- -uint64_t imgtool::stream::transfer_all(imgtool::stream &dest, imgtool::stream &source) +uint64_t stream::transfer_all(stream &dest, stream &source) { return transfer(dest, source, source.size()); } //------------------------------------------------- -// crc -//------------------------------------------------- - -int imgtool::stream::crc(unsigned long *result) -{ - size_t sz; - void *ptr; - - switch(imgtype) - { - case IMG_MEM: - *result = crc32(0, (unsigned char *) buffer, (size_t) filesize); - break; - - default: - sz = size(); - ptr = malloc(sz); - if (!ptr) - return IMGTOOLERR_OUTOFMEMORY; - seek(0, SEEK_SET); - if (read(ptr, sz) != sz) - { - free(ptr); - return IMGTOOLERR_READERROR; - } - *result = crc32(0, (const Bytef*)ptr, sz); - free(ptr); - break; - } - return 0; -} - - -//------------------------------------------------- -// file_crc -//------------------------------------------------- - -int imgtool::stream::file_crc(const char *fname, unsigned long *result) -{ - int err; - imgtool::stream::ptr f; - - f = imgtool::stream::open(fname, OSD_FOPEN_READ); - if (!f) - return IMGTOOLERR_FILENOTFOUND; - - err = f->crc(result); - return err; -} - - -//------------------------------------------------- // fill //------------------------------------------------- -uint64_t imgtool::stream::fill(unsigned char b, uint64_t sz) +uint64_t stream::fill(unsigned char b, uint64_t sz) { uint64_t outsz; char buf[1024]; @@ -492,7 +579,7 @@ uint64_t imgtool::stream::fill(unsigned char b, uint64_t sz) // is_read_only //------------------------------------------------- -bool imgtool::stream::is_read_only() +bool stream::is_read_only() { return write_protect; } @@ -502,7 +589,7 @@ bool imgtool::stream::is_read_only() // putc //------------------------------------------------- -uint32_t imgtool::stream::putc(char c) +uint32_t stream::putc(char c) { return write(&c, 1); } @@ -512,7 +599,7 @@ uint32_t imgtool::stream::putc(char c) // puts //------------------------------------------------- -uint32_t imgtool::stream::puts(const char *s) +uint32_t stream::puts(const char *s) { return write(s, strlen(s)); } @@ -522,7 +609,7 @@ uint32_t imgtool::stream::puts(const char *s) // printf //------------------------------------------------- -uint32_t imgtool::stream::printf(const char *fmt, ...) +uint32_t stream::printf(const char *fmt, ...) { va_list va; char buf[256]; @@ -533,3 +620,5 @@ uint32_t imgtool::stream::printf(const char *fmt, ...) return puts(buf); } + +} // namespace imgtool diff --git a/src/tools/imgtool/stream.h b/src/tools/imgtool/stream.h index 2b7afbacd5e..8083dbac9d9 100644 --- a/src/tools/imgtool/stream.h +++ b/src/tools/imgtool/stream.h @@ -7,77 +7,84 @@ Code for implementing Imgtool streams ***************************************************************************/ +#ifndef MAME_TOOLS_IMGTOOL_STREAM_H +#define MAME_TOOLS_IMGTOOL_STREAM_H -#ifndef STREAM_H -#define STREAM_H +#pragma once -#include "imgterrs.h" -#include "corefile.h" +#include "utilfwd.h" -namespace imgtool +#include "osdcomm.h" + +#include <cstdint> +#include <memory> +#include <string> + + +namespace imgtool { + +class stream { - class stream +public: + typedef std::unique_ptr<stream> ptr; + + ~stream(); + + static imgtool::stream::ptr open(const std::string &filename, int read_or_write); /* similar params to mame_fopen */ + static imgtool::stream::ptr open_write_stream(int filesize); + static imgtool::stream::ptr open_mem(void *buf, size_t sz); + + util::core_file *core_file(); + uint32_t read(void *buf, uint32_t sz); + uint32_t write(const void *buf, uint32_t sz); + uint64_t size() const; + int seek(int64_t pos, int where); + uint64_t tell(); + uint32_t putc(char c); + uint32_t puts(const char *s); + uint32_t printf(const char *fmt, ...) ATTR_PRINTF(2, 3); + + // transfers sz bytes from source to dest + static uint64_t transfer(imgtool::stream &dest, imgtool::stream &source, uint64_t sz); + static uint64_t transfer_all(imgtool::stream &dest, imgtool::stream &source); + + // fills sz bytes with b + uint64_t fill(unsigned char b, uint64_t sz); + + // returns whether a stream is read only or not + bool is_read_only(); + +private: + enum imgtype_t { - public: - typedef std::unique_ptr<stream> ptr; - - ~stream(); - - static imgtool::stream::ptr open(const std::string &filename, int read_or_write); /* similar params to mame_fopen */ - static imgtool::stream::ptr open_write_stream(int filesize); - static imgtool::stream::ptr open_mem(void *buf, size_t sz); - - util::core_file *core_file(); - uint32_t read(void *buf, uint32_t sz); - uint32_t write(const void *buf, uint32_t sz); - uint64_t size() const; - int seek(int64_t pos, int where); - uint64_t tell(); - void *getptr(); - uint32_t putc(char c); - uint32_t puts(const char *s); - uint32_t printf(const char *fmt, ...) ATTR_PRINTF(2, 3); - - // transfers sz bytes from source to dest - static uint64_t transfer(imgtool::stream &dest, imgtool::stream &source, uint64_t sz); - static uint64_t transfer_all(imgtool::stream &dest, imgtool::stream &source); - - // fills sz bytes with b - uint64_t fill(unsigned char b, uint64_t sz); - - // returns the CRC of a file - int crc(unsigned long *result); - static int file_crc(const char *fname, unsigned long *result); - - // returns whether a stream is read only or not - bool is_read_only(); - - private: - enum imgtype_t - { - IMG_FILE, - IMG_MEM - }; - - imgtype_t imgtype; - bool write_protect; - std::uint64_t position; - std::uint64_t filesize; - - util::core_file::ptr file; - std::uint8_t *buffer; - - // ctors - stream(bool wp); - stream(bool wp, util::core_file::ptr &&f); - stream(bool wp, std::size_t size); - stream(bool wp, std::size_t size, void *buf); - - // private methods - static stream::ptr open_zip(const std::string &zipname, const char *subname, int read_or_write); + IMG_FILE, + IMG_MEM }; -} + imgtype_t imgtype; + bool write_protect; + std::uint64_t position; + std::uint64_t filesize; + + std::unique_ptr<util::core_file> file; + std::uint8_t *buffer; + + // ctors + stream(bool wp); + stream(bool wp, std::unique_ptr<util::core_file> &&f); + stream(bool wp, std::size_t size); + stream(bool wp, std::size_t size, void *buf); + + // private methods + static stream::ptr open_zip(const std::string &zipname, const char *subname, int read_or_write); +}; + + +std::unique_ptr<util::random_read> stream_read(stream::ptr &&s, std::uint8_t filler) noexcept; +std::unique_ptr<util::random_read> stream_read(stream &s, std::uint8_t filler) noexcept; +std::unique_ptr<util::random_read_write> stream_read_write(stream::ptr &&s, std::uint8_t filler) noexcept; +std::unique_ptr<util::random_read_write> stream_read_write(stream &s, std::uint8_t filler) noexcept; +} // namespace imgtool -#endif /* STREAM_H */ +#endif // MAME_TOOLS_IMGTOOL_STREAM_H diff --git a/src/tools/jedutil.cpp b/src/tools/jedutil.cpp index d1c49ec7a79..f9f57ff8fed 100644 --- a/src/tools/jedutil.cpp +++ b/src/tools/jedutil.cpp @@ -54,11 +54,19 @@ PAL16V8R = QP20 QF2194 PALCE16V8 = QP20 QF2194 GAL16V8A = QP20 QF2194 + ATF16V8B = QP20 QF2194 18CV8 = QP20 QF2696 AMPAL18P8 = QP20 QF2600 + 5C032 = QP20 + + PLUS16L8 = QP20 + PLUS16R4 = QP20 + PLUS16R6 = QP20 + PLUS16R8 = QP20 + EPL10P8 = QP20 EPL12P6 = QP20 EPL14P4 = QP20 @@ -68,6 +76,9 @@ EPL16RP6 = QP20 EPL16RP4 = QP20 + PAL16A4 = QP20 + PAL16X4 = QP20 + 24-pin devices: PAL6L16 = QP24 QF0192 PAL8L14 = QP24 QF0224 @@ -94,10 +105,22 @@ PAL20X8 = QP24 QF1600 PAL20X10 = QP24 QF1600 - PAL22V10 = QP24 QF5828? - GAL20V8A = QP24 QF2706 + PALCE20V8 = QP24 QF2706 + ATF20V10B = QP24 QF2706 + GAL22V10 = QP24 QF5892 + ATF22V10C = QP24 QF5892 (GAL Mode) + + PALCE22V10 = QP24 QF5828 + PAL22V10 = QP24 QF5828 + ATF22V10C = QP24 QF5828 (PAL Mode) + + ATF22V10C = QP24 QF5893 (Power Down Mode) + + PLS173 = QP24 + + GAL6001 = QP24 28-pin devices: PLS100 = QP28 QF1928 (Tri-State) @@ -112,11 +135,17 @@ ***************************************************************************/ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> +#include <cstdint> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <cctype> + +#include <set> +#include <vector> + #include "corestr.h" +#include "ioprocs.h" #include "jedparse.h" #include "plaparse.h" @@ -259,6 +288,11 @@ struct _pin_output_config }; + +typedef std::vector<const pal_data*> pal_data_vector; + + + /*************************************************************************** FUNCTION PROTOTYPES ***************************************************************************/ @@ -276,7 +310,6 @@ static void print_pal16l8_product_terms(const pal_data* pal, const jed_data* jed static void print_pal16r4_product_terms(const pal_data* pal, const jed_data* jed); static void print_pal16r6_product_terms(const pal_data* pal, const jed_data* jed); static void print_pal16r8_product_terms(const pal_data* pal, const jed_data* jed); -static void print_palce16v8_product_terms(const pal_data* pal, const jed_data* jed); static void print_gal16v8_product_terms(const pal_data* pal, const jed_data* jed); static void print_peel18cv8_product_terms(const pal_data* pal, const jed_data* jed); static void print_ampal18p8_product_terms(const pal_data* pal, const jed_data* jed); @@ -290,6 +323,10 @@ static void print_pal20ra10_product_terms(const pal_data* pal, const jed_data* j static void print_pal20x4_product_terms(const pal_data* pal, const jed_data* jed); static void print_pal20x8_product_terms(const pal_data* pal, const jed_data* jed); static void print_pal20x10_product_terms(const pal_data* pal, const jed_data* jed); +static void print_gal20v8_product_terms(const pal_data* pal, const jed_data* jed); +static void print_palce22v10_pal22v10_product_terms(const pal_data* pal, const jed_data* jed); +static void print_gal22v10_product_terms(const pal_data* pal, const jed_data* jed); +static void print_atf22v10_power_down_mode_product_terms(const pal_data* pal, const jed_data* jed); static void print_82s153_pls153_product_terms(const pal_data* pal, const jed_data* jed); static void print_ck2605_product_terms(const pal_data* pal, const jed_data* jed); #if defined(ricoh_pals) @@ -339,7 +376,6 @@ static void config_pal16l8_pins(const pal_data* pal, const jed_data* jed); static void config_pal16r4_pins(const pal_data* pal, const jed_data* jed); static void config_pal16r6_pins(const pal_data* pal, const jed_data* jed); static void config_pal16r8_pins(const pal_data* pal, const jed_data* jed); -static void config_palce16v8_pins(const pal_data* pal, const jed_data* jed); static void config_gal16v8_pins(const pal_data* pal, const jed_data* jed); static void config_peel18cv8_pins(const pal_data* pal, const jed_data* jed); static void config_ampal18p8_pins(const pal_data* pal, const jed_data* jed); @@ -353,6 +389,10 @@ static void config_pal20ra10_pins(const pal_data* pal, const jed_data* jed); static void config_pal20x4_pins(const pal_data* pal, const jed_data* jed); static void config_pal20x8_pins(const pal_data* pal, const jed_data* jed); static void config_pal20x10_pins(const pal_data* pal, const jed_data* jed); +static void config_gal20v8_pins(const pal_data* pal, const jed_data* jed); +static void config_palce22v10_pal22v10_pins(const pal_data* pal, const jed_data* jed); +static void config_gal22v10_pins(const pal_data* pal, const jed_data* jed); +static void config_atf22v10_power_down_mode_pins(const pal_data* pal, const jed_data* jed); static void config_82s153_pls153_pins(const pal_data* pal, const jed_data* jed); static void config_ck2605_pins(const pal_data* pal, const jed_data* jed); #if defined(ricoh_pals) @@ -393,6 +433,10 @@ static int is_gal16v8_product_term_enabled(const pal_data* pal, const jed_data* +static int is_gal20v8_product_term_enabled(const pal_data* pal, const jed_data* jed, uint16_t fuserow); + + + static uint16_t get_peel18cv8_pin_fuse_state(const pal_data* pal, const jed_data* jed, uint16_t pin, uint16_t fuserow); @@ -401,9 +445,6 @@ static uint16_t get_peel18cv8_pin_fuse_state(const pal_data* pal, const jed_data GLOBAL VARIABLES ***************************************************************************/ -static uint8_t *srcbuf; -static size_t srcbuflen; - static uint8_t *dstbuf; static size_t dstbuflen; @@ -513,16 +554,6 @@ static pin_fuse_rows pal16r8pinfuserows[] = { {18, NO_OUTPUT_ENABLE_FUSE_ROW, 256, 480}, /* Registered Output */ {19, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 224}}; /* Registered Output */ -static pin_fuse_rows palce16v8pinfuserows[] = { - {12, 0, 0, 0}, - {13, 0, 0, 0}, - {14, 0, 0, 0}, - {15, 0, 0, 0}, - {16, 0, 0, 0}, - {17, 0, 0, 0}, - {18, 0, 0, 0}, - {19, 0, 0, 0}}; - static pin_fuse_rows gal16v8pinfuserows[] = { {12, 0, 0, 0}, {13, 0, 0, 0}, @@ -665,6 +696,52 @@ static pin_fuse_rows pal20x10pinfuserows[] = { {22, NO_OUTPUT_ENABLE_FUSE_ROW, 160, 280}, /* Registered Output */ {23, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 120}}; /* Registered Output */ +static pin_fuse_rows gal20v8pinfuserows[] = { + {15, 0, 0, 0}, + {16, 0, 0, 0}, + {17, 0, 0, 0}, + {18, 0, 0, 0}, + {19, 0, 0, 0}, + {20, 0, 0, 0}, + {21, 0, 0, 0}, + {22, 0, 0, 0}}; + +static pin_fuse_rows palce22v10_pal22v10pinfuserows[] = { + {14, 5368, 5412, 5720}, + {15, 4884, 4928, 5324}, + {16, 4312, 4356, 4840}, + {17, 3652, 3696, 4268}, + {18, 2904, 2948, 3608}, + {19, 2156, 2200, 2860}, + {20, 1496, 1540, 2112}, + {21, 924, 968, 1452}, + {22, 440, 484, 880}, + {23, 44, 88, 396}}; + +static pin_fuse_rows gal22v10pinfuserows[] = { + {14, 5368, 5412, 5720}, + {15, 4884, 4928, 5324}, + {16, 4312, 4356, 4840}, + {17, 3652, 3696, 4268}, + {18, 2904, 2948, 3608}, + {19, 2156, 2200, 2860}, + {20, 1496, 1540, 2112}, + {21, 924, 968, 1452}, + {22, 440, 484, 880}, + {23, 44, 88, 396}}; + +static pin_fuse_rows atf22v10powerdownmodepinfuserows[] = { + {14, 5368, 5412, 5720}, + {15, 4884, 4928, 5324}, + {16, 4312, 4356, 4840}, + {17, 3652, 3696, 4268}, + {18, 2904, 2948, 3608}, + {19, 2156, 2200, 2860}, + {20, 1496, 1540, 2112}, + {21, 924, 968, 1452}, + {22, 440, 484, 880}, + {23, 44, 88, 396}}; + static pin_fuse_rows _82s153_pls153pinfuserows[] = { {9, 1472, 0, 0}, {11, 1508, 0, 0}, @@ -1161,24 +1238,6 @@ static pin_fuse_columns pal16r8pinfusecolumns[] = { {18, 7, 6}, /* Registered Output */ {19, 3, 2}}; /* Registered Output */ -static pin_fuse_columns palce16v8pinfusecolumns[] = { - {2, 1, 0}, - {3, 5, 4}, - {4, 9, 8}, - {5, 13, 12}, - {6, 17, 16}, - {7, 21, 20}, - {8, 25, 24}, - {9, 29, 28}, - {12, 31, 30}, - {13, 27, 26}, - {14, 23, 22}, - {15, 19, 18}, - {16, 15, 14}, - {17, 11, 10}, - {18, 7, 6}, - {19, 3, 2}}; - static pin_fuse_columns gal16v8pinfusecolumns[] = { {0, 0, 0}, {0, 0, 0}, @@ -1456,6 +1515,100 @@ static pin_fuse_columns pal20x10pinfusecolumns[] = { {23, 3, 2} }; +static pin_fuse_columns gal20v8pinfusecolumns[] = { + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}}; + +static pin_fuse_columns palce22v10_pal22v10pinfusecolumns[] = { + {1, 1, 0}, + {2, 5, 4}, + {3, 9, 8}, + {4, 13, 12}, + {5, 17, 16}, + {6, 21, 20}, + {7, 25, 24}, + {8, 29, 28}, + {9, 33, 32}, + {10, 37, 36}, + {11, 41, 40}, + {13, 43, 42}, + {14, 39, 38}, + {15, 35, 34}, + {16, 31, 30}, + {17, 27, 26}, + {18, 23, 22}, + {19, 19, 18}, + {20, 15, 14}, + {21, 11, 10}, + {22, 7, 6}, + {23, 3, 2}}; + +static pin_fuse_columns gal22v10pinfusecolumns[] = { + {1, 1, 0}, + {2, 5, 4}, + {3, 9, 8}, + {4, 13, 12}, + {5, 17, 16}, + {6, 21, 20}, + {7, 25, 24}, + {8, 29, 28}, + {9 , 33, 32}, + {10, 37, 36}, + {11, 41, 40}, + {13, 43, 42}, + {14, 39, 38}, + {15, 35, 34}, + {16, 31, 30}, + {17, 27, 26}, + {18, 23, 22}, + {19, 19, 18}, + {20, 15, 14}, + {21, 11, 10}, + {22, 7, 6}, + {23, 3, 2}}; + +static pin_fuse_columns atf22v10powerdownmodepinfusecolumns[] = { + {1, 1, 0}, + {2, 5, 4}, + {3, 9, 8}, + {4, 13, 12}, + {5, 17, 16}, + {6, 21, 20}, + {7, 25, 24}, + {8, 29, 28}, + {9 , 33, 32}, + {10, 37, 36}, + {11, 41, 40}, + {13, 43, 42}, + {14, 39, 38}, + {15, 35, 34}, + {16, 31, 30}, + {17, 27, 26}, + {18, 23, 22}, + {19, 19, 18}, + {20, 15, 14}, + {21, 11, 10}, + {22, 7, 6}, + {23, 3, 2}}; + static pin_fuse_columns _82s153_pls153pinfusecolumns[] = { {1, 1, 0}, {2, 3, 2}, @@ -1976,443 +2129,510 @@ static pin_fuse_columns _82s100_pls100_pinfusecolumns[] = { static pal_data paldata[] = { {"PAL10L8", 320, - pal10l8pinfuserows, ARRAY_LENGTH(pal10l8pinfuserows), - pal10l8pinfusecolumns, ARRAY_LENGTH(pal10l8pinfusecolumns), + pal10l8pinfuserows, std::size(pal10l8pinfuserows), + pal10l8pinfusecolumns, std::size(pal10l8pinfusecolumns), print_pal10l8_product_terms, config_pal10l8_pins, nullptr, nullptr}, {"PAL10H8", 320, - pal10h8pinfuserows, ARRAY_LENGTH(pal10h8pinfuserows), - pal10h8pinfusecolumns, ARRAY_LENGTH(pal10h8pinfusecolumns), + pal10h8pinfuserows, std::size(pal10h8pinfuserows), + pal10h8pinfusecolumns, std::size(pal10h8pinfusecolumns), print_pal10h8_product_terms, config_pal10h8_pins, nullptr, nullptr}, {"PAL12H6", 384, - pal12h6pinfuserows, ARRAY_LENGTH(pal12h6pinfuserows), - pal12h6pinfusecolumns, ARRAY_LENGTH(pal12h6pinfusecolumns), + pal12h6pinfuserows, std::size(pal12h6pinfuserows), + pal12h6pinfusecolumns, std::size(pal12h6pinfusecolumns), print_pal12h6_product_terms, config_pal12h6_pins, nullptr, nullptr}, {"PAL14H4", 448, - pal14h4pinfuserows, ARRAY_LENGTH(pal14h4pinfuserows), - pal14h4pinfusecolumns, ARRAY_LENGTH(pal14h4pinfusecolumns), + pal14h4pinfuserows, std::size(pal14h4pinfuserows), + pal14h4pinfusecolumns, std::size(pal14h4pinfusecolumns), print_pal14h4_product_terms, config_pal14h4_pins, nullptr, nullptr}, {"PAL16H2", 512, - pal16h2pinfuserows, ARRAY_LENGTH(pal16h2pinfuserows), - pal16h2pinfusecolumns, ARRAY_LENGTH(pal16h2pinfusecolumns), + pal16h2pinfuserows, std::size(pal16h2pinfuserows), + pal16h2pinfusecolumns, std::size(pal16h2pinfusecolumns), print_pal16h2_product_terms, config_pal16h2_pins, nullptr, nullptr}, {"PAL16C1", 512, - pal16c1pinfuserows, ARRAY_LENGTH(pal16c1pinfuserows), - pal16c1pinfusecolumns, ARRAY_LENGTH(pal16c1pinfusecolumns), + pal16c1pinfuserows, std::size(pal16c1pinfuserows), + pal16c1pinfusecolumns, std::size(pal16c1pinfusecolumns), print_pal16c1_product_terms, config_pal16c1_pins, nullptr, nullptr}, {"PAL12L6", 384, - pal12l6pinfuserows, ARRAY_LENGTH(pal12l6pinfuserows), - pal12l6pinfusecolumns, ARRAY_LENGTH(pal12l6pinfusecolumns), + pal12l6pinfuserows, std::size(pal12l6pinfuserows), + pal12l6pinfusecolumns, std::size(pal12l6pinfusecolumns), print_pal12l6_product_terms, config_pal12l6_pins, nullptr, nullptr}, {"PAL14L4", 448, - pal14l4pinfuserows, ARRAY_LENGTH(pal14l4pinfuserows), - pal14l4pinfusecolumns, ARRAY_LENGTH(pal14l4pinfusecolumns), + pal14l4pinfuserows, std::size(pal14l4pinfuserows), + pal14l4pinfusecolumns, std::size(pal14l4pinfusecolumns), print_pal14l4_product_terms, config_pal14l4_pins, nullptr, nullptr}, {"PAL16L2", 512, - pal16l2pinfuserows, ARRAY_LENGTH(pal16l2pinfuserows), - pal16l2pinfusecolumns, ARRAY_LENGTH(pal16l2pinfusecolumns), + pal16l2pinfuserows, std::size(pal16l2pinfuserows), + pal16l2pinfusecolumns, std::size(pal16l2pinfusecolumns), print_pal16l2_product_terms, config_pal16l2_pins, nullptr, nullptr}, /*{"15S8", 0, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL},*/ {"PAL16L8", 2048, - pal16l8pinfuserows, ARRAY_LENGTH(pal16l8pinfuserows), - pal16l8pinfusecolumns, ARRAY_LENGTH(pal16l8pinfusecolumns), + pal16l8pinfuserows, std::size(pal16l8pinfuserows), + pal16l8pinfusecolumns, std::size(pal16l8pinfusecolumns), print_pal16l8_product_terms, config_pal16l8_pins, nullptr, nullptr}, {"PAL16R4", 2048, - pal16r4pinfuserows, ARRAY_LENGTH(pal16r4pinfuserows), - pal16r4pinfusecolumns, ARRAY_LENGTH(pal16r4pinfusecolumns), + pal16r4pinfuserows, std::size(pal16r4pinfuserows), + pal16r4pinfusecolumns, std::size(pal16r4pinfusecolumns), print_pal16r4_product_terms, config_pal16r4_pins, nullptr, nullptr}, {"PAL16R6", 2048, - pal16r6pinfuserows, ARRAY_LENGTH(pal16r6pinfuserows), - pal16r6pinfusecolumns, ARRAY_LENGTH(pal16r6pinfusecolumns), + pal16r6pinfuserows, std::size(pal16r6pinfuserows), + pal16r6pinfusecolumns, std::size(pal16r6pinfusecolumns), print_pal16r6_product_terms, config_pal16r6_pins, nullptr, nullptr}, {"PAL16R8", 2048, - pal16r8pinfuserows, ARRAY_LENGTH(pal16r8pinfuserows), - pal16r8pinfusecolumns, ARRAY_LENGTH(pal16r8pinfusecolumns), + pal16r8pinfuserows, std::size(pal16r8pinfuserows), + pal16r8pinfusecolumns, std::size(pal16r8pinfusecolumns), print_pal16r8_product_terms, config_pal16r8_pins, nullptr, nullptr}, /*{"PAL16RA8", 0, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL}, - {"PAL16V8R", 0, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL},*/ + {"PAL16V8R", 0, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL},*/ // PAL16V8 same fusemap as GAL16V8? {"PALCE16V8", 2194, - palce16v8pinfuserows, ARRAY_LENGTH(palce16v8pinfuserows), - palce16v8pinfusecolumns, ARRAY_LENGTH(palce16v8pinfusecolumns), - print_palce16v8_product_terms, - config_palce16v8_pins, + gal16v8pinfuserows, std::size(gal16v8pinfuserows), + gal16v8pinfusecolumns, std::size(gal16v8pinfusecolumns), + print_gal16v8_product_terms, + config_gal16v8_pins, nullptr, nullptr}, {"GAL16V8", 2194, - gal16v8pinfuserows, ARRAY_LENGTH(gal16v8pinfuserows), - gal16v8pinfusecolumns, ARRAY_LENGTH(gal16v8pinfusecolumns), + gal16v8pinfuserows, std::size(gal16v8pinfuserows), + gal16v8pinfusecolumns, std::size(gal16v8pinfusecolumns), + print_gal16v8_product_terms, + config_gal16v8_pins, + is_gal16v8_product_term_enabled, + nullptr}, + {"ATF16V8", 2194, + gal16v8pinfuserows, std::size(gal16v8pinfuserows), + gal16v8pinfusecolumns, std::size(gal16v8pinfusecolumns), print_gal16v8_product_terms, config_gal16v8_pins, is_gal16v8_product_term_enabled, nullptr}, {"18CV8", 2696, - peel18cv8pinfuserows, ARRAY_LENGTH(peel18cv8pinfuserows), - peel18cv8pinfusecolumns, ARRAY_LENGTH(peel18cv8pinfusecolumns), + peel18cv8pinfuserows, std::size(peel18cv8pinfuserows), + peel18cv8pinfusecolumns, std::size(peel18cv8pinfusecolumns), print_peel18cv8_product_terms, config_peel18cv8_pins, nullptr, get_peel18cv8_pin_fuse_state}, {"AMPAL18P8", 2600, - ampal18p8pinfuserows, ARRAY_LENGTH(ampal18p8pinfuserows), - ampal18p8pinfusecolumns, ARRAY_LENGTH(ampal18p8pinfusecolumns), + ampal18p8pinfuserows, std::size(ampal18p8pinfuserows), + ampal18p8pinfusecolumns, std::size(ampal18p8pinfusecolumns), print_ampal18p8_product_terms, config_ampal18p8_pins, nullptr, nullptr}, {"GAL18V10", 3540, - gal18v10pinfuserows, ARRAY_LENGTH(gal18v10pinfuserows), - gal18v10pinfusecolumns, ARRAY_LENGTH(gal18v10pinfusecolumns), + gal18v10pinfuserows, std::size(gal18v10pinfuserows), + gal18v10pinfusecolumns, std::size(gal18v10pinfusecolumns), print_gal18v10_product_terms, config_gal18v10_pins, nullptr, nullptr}, {"PAL20L8", 2560, - pal20l8pinfuserows, ARRAY_LENGTH(pal20l8pinfuserows), - pal20l8pinfusecolumns, ARRAY_LENGTH(pal20l8pinfusecolumns), + pal20l8pinfuserows, std::size(pal20l8pinfuserows), + pal20l8pinfusecolumns, std::size(pal20l8pinfusecolumns), print_pal20l8_product_terms, config_pal20l8_pins, nullptr, nullptr}, {"PAL20L10", 1600, - pal20l10pinfuserows, ARRAY_LENGTH(pal20l10pinfuserows), - pal20l10pinfusecolumns, ARRAY_LENGTH(pal20l10pinfusecolumns), + pal20l10pinfuserows, std::size(pal20l10pinfuserows), + pal20l10pinfusecolumns, std::size(pal20l10pinfusecolumns), print_pal20l10_product_terms, config_pal20l10_pins, nullptr, nullptr}, {"PAL20R4", 2560, - pal20r4pinfuserows, ARRAY_LENGTH(pal20r4pinfuserows), - pal20r4pinfusecolumns, ARRAY_LENGTH(pal20r4pinfusecolumns), + pal20r4pinfuserows, std::size(pal20r4pinfuserows), + pal20r4pinfusecolumns, std::size(pal20r4pinfusecolumns), print_pal20r4_product_terms, config_pal20r4_pins, nullptr, nullptr}, {"PAL20R6", 2560, - pal20r6pinfuserows, ARRAY_LENGTH(pal20r6pinfuserows), - pal20r6pinfusecolumns, ARRAY_LENGTH(pal20r6pinfusecolumns), + pal20r6pinfuserows, std::size(pal20r6pinfuserows), + pal20r6pinfusecolumns, std::size(pal20r6pinfusecolumns), print_pal20r6_product_terms, config_pal20r6_pins, nullptr, nullptr}, {"PAL20R8", 2560, - pal20r8pinfuserows, ARRAY_LENGTH(pal20r8pinfuserows), - pal20r8pinfusecolumns, ARRAY_LENGTH(pal20r8pinfusecolumns), + pal20r8pinfuserows, std::size(pal20r8pinfuserows), + pal20r8pinfusecolumns, std::size(pal20r8pinfusecolumns), print_pal20r8_product_terms, config_pal20r8_pins, nullptr, nullptr}, {"PAL20RA10", 3210, - pal20ra10pinfuserows, ARRAY_LENGTH(pal20ra10pinfuserows), - pal20ra10pinfusecolumns, ARRAY_LENGTH(pal20ra10pinfusecolumns), + pal20ra10pinfuserows, std::size(pal20ra10pinfuserows), + pal20ra10pinfusecolumns, std::size(pal20ra10pinfusecolumns), print_pal20ra10_product_terms, config_pal20ra10_pins, nullptr, nullptr }, {"PAL20X4", 1600, - pal20x4pinfuserows, ARRAY_LENGTH(pal20x4pinfuserows), - pal20x4pinfusecolumns, ARRAY_LENGTH(pal20x4pinfusecolumns), + pal20x4pinfuserows, std::size(pal20x4pinfuserows), + pal20x4pinfusecolumns, std::size(pal20x4pinfusecolumns), print_pal20x4_product_terms, config_pal20x4_pins, nullptr, nullptr}, {"PAL20X8", 1600, - pal20x8pinfuserows, ARRAY_LENGTH(pal20x8pinfuserows), - pal20x8pinfusecolumns, ARRAY_LENGTH(pal20x8pinfusecolumns), + pal20x8pinfuserows, std::size(pal20x8pinfuserows), + pal20x8pinfusecolumns, std::size(pal20x8pinfusecolumns), print_pal20x8_product_terms, config_pal20x8_pins, nullptr, nullptr}, {"PAL20X10", 1600, - pal20x10pinfuserows, ARRAY_LENGTH(pal20x10pinfuserows), - pal20x10pinfusecolumns, ARRAY_LENGTH(pal20x10pinfusecolumns), + pal20x10pinfuserows, std::size(pal20x10pinfuserows), + pal20x10pinfusecolumns, std::size(pal20x10pinfusecolumns), print_pal20x10_product_terms, config_pal20x10_pins, nullptr, nullptr}, - /*{"PAL22V10", 0, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL}, - {"GAL20V8A", 0, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL}, - {"GAL22V10", 0, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL},*/ + {"GAL20V8", 2706, + gal20v8pinfuserows, std::size(gal20v8pinfuserows), + gal20v8pinfusecolumns, std::size(gal20v8pinfusecolumns), + print_gal20v8_product_terms, + config_gal20v8_pins, + is_gal20v8_product_term_enabled, + nullptr}, + {"PALCE20V8", 2706, + gal20v8pinfuserows, std::size(gal20v8pinfuserows), + gal20v8pinfusecolumns, std::size(gal20v8pinfusecolumns), + print_gal20v8_product_terms, + config_gal20v8_pins, + is_gal20v8_product_term_enabled, + nullptr}, + {"ATF20V10", 2706, + gal20v8pinfuserows, std::size(gal20v8pinfuserows), + gal20v8pinfusecolumns, std::size(gal20v8pinfusecolumns), + print_gal20v8_product_terms, + config_gal20v8_pins, + is_gal20v8_product_term_enabled, + nullptr}, + {"PAL22V10", 5828, + palce22v10_pal22v10pinfuserows, std::size(palce22v10_pal22v10pinfuserows), + palce22v10_pal22v10pinfusecolumns, std::size(palce22v10_pal22v10pinfusecolumns), + print_palce22v10_pal22v10_product_terms, + config_palce22v10_pal22v10_pins, + nullptr, + nullptr}, + {"PALCE22V10", 5828, + palce22v10_pal22v10pinfuserows, std::size(palce22v10_pal22v10pinfuserows), + palce22v10_pal22v10pinfusecolumns, std::size(palce22v10_pal22v10pinfusecolumns), + print_palce22v10_pal22v10_product_terms, + config_palce22v10_pal22v10_pins, + nullptr, + nullptr}, + {"ATF22V10", 5828, + palce22v10_pal22v10pinfuserows, std::size(palce22v10_pal22v10pinfuserows), + palce22v10_pal22v10pinfusecolumns, std::size(palce22v10_pal22v10pinfusecolumns), + print_palce22v10_pal22v10_product_terms, + config_palce22v10_pal22v10_pins, + nullptr, + nullptr}, + {"GAL22V10", 5892, + gal22v10pinfuserows, std::size(gal22v10pinfuserows), + gal22v10pinfusecolumns, std::size(gal22v10pinfusecolumns), + print_gal22v10_product_terms, + config_gal22v10_pins, + nullptr, + nullptr}, + {"ATF22V10", 5892, + gal22v10pinfuserows, std::size(gal22v10pinfuserows), + gal22v10pinfusecolumns, std::size(gal22v10pinfusecolumns), + print_gal22v10_product_terms, + config_gal22v10_pins, + nullptr, + nullptr}, + {"ATF22V10", 5893, + atf22v10powerdownmodepinfuserows, std::size(atf22v10powerdownmodepinfuserows), + atf22v10powerdownmodepinfusecolumns, std::size(atf22v10powerdownmodepinfusecolumns), + print_atf22v10_power_down_mode_product_terms, + config_atf22v10_power_down_mode_pins, + nullptr, + nullptr}, {"82S153", 1842, - _82s153_pls153pinfuserows, ARRAY_LENGTH(_82s153_pls153pinfuserows), - _82s153_pls153pinfusecolumns, ARRAY_LENGTH(_82s153_pls153pinfusecolumns), + _82s153_pls153pinfuserows, std::size(_82s153_pls153pinfuserows), + _82s153_pls153pinfusecolumns, std::size(_82s153_pls153pinfusecolumns), print_82s153_pls153_product_terms, config_82s153_pls153_pins, nullptr, nullptr}, {"PLS153", 1842, - _82s153_pls153pinfuserows, ARRAY_LENGTH(_82s153_pls153pinfuserows), - _82s153_pls153pinfusecolumns, ARRAY_LENGTH(_82s153_pls153pinfusecolumns), + _82s153_pls153pinfuserows, std::size(_82s153_pls153pinfuserows), + _82s153_pls153pinfusecolumns, std::size(_82s153_pls153pinfusecolumns), print_82s153_pls153_product_terms, config_82s153_pls153_pins, nullptr, nullptr}, {"CK2605", 1106, - ck2605pinfuserows, ARRAY_LENGTH(ck2605pinfuserows), - ck2605pinfusecolumns, ARRAY_LENGTH(ck2605pinfusecolumns), + ck2605pinfuserows, std::size(ck2605pinfuserows), + ck2605pinfusecolumns, std::size(ck2605pinfusecolumns), print_ck2605_product_terms, config_ck2605_pins, nullptr, nullptr}, #if defined(ricoh_pals) {"EPL10P8", 664, - epl10p8pinfuserows, ARRAY_LENGTH(epl10p8pinfuserows), - epl10p8pinfusecolumns, ARRAY_LENGTH(epl10p8pinfusecolumns), + epl10p8pinfuserows, std::size(epl10p8pinfuserows), + epl10p8pinfusecolumns, std::size(epl10p8pinfusecolumns), print_epl10p8_product_terms, config_epl10p8_pins, nullptr, nullptr}, {"EPL12P6", 786, - epl12p6pinfuserows, ARRAY_LENGTH(epl12p6pinfuserows), - epl12p6pinfusecolumns, ARRAY_LENGTH(epl12p6pinfusecolumns), + epl12p6pinfuserows, std::size(epl12p6pinfuserows), + epl12p6pinfusecolumns, std::size(epl12p6pinfusecolumns), print_epl12p6_product_terms, config_epl12p6_pins, nullptr, nullptr}, {"EPL14P4", 908, - epl14p4pinfuserows, ARRAY_LENGTH(epl14p4pinfuserows), - epl14p4pinfusecolumns, ARRAY_LENGTH(epl14p4pinfusecolumns), + epl14p4pinfuserows, std::size(epl14p4pinfuserows), + epl14p4pinfusecolumns, std::size(epl14p4pinfusecolumns), print_epl14p4_product_terms, config_epl14p4_pins, nullptr, nullptr}, {"EPL16P2", 1030, - epl16p2pinfuserows, ARRAY_LENGTH(epl16p2pinfuserows), - epl16p2pinfusecolumns, ARRAY_LENGTH(epl16p2pinfusecolumns), + epl16p2pinfuserows, std::size(epl16p2pinfuserows), + epl16p2pinfusecolumns, std::size(epl16p2pinfusecolumns), print_epl16p2_product_terms, config_epl16p2_pins, nullptr, nullptr}, {"EPL16P8", 2072, - epl16p8pinfuserows, ARRAY_LENGTH(epl16p8pinfuserows), - epl16p8pinfusecolumns, ARRAY_LENGTH(epl16p8pinfusecolumns), + epl16p8pinfuserows, std::size(epl16p8pinfuserows), + epl16p8pinfusecolumns, std::size(epl16p8pinfusecolumns), print_epl16p8_product_terms, config_epl16p8_pins, nullptr, nullptr}, {"EPL16RP8", 2072, - epl16rp8pinfuserows, ARRAY_LENGTH(epl16rp8pinfuserows), - epl16rp8pinfusecolumns, ARRAY_LENGTH(epl16rp8pinfusecolumns), + epl16rp8pinfuserows, std::size(epl16rp8pinfuserows), + epl16rp8pinfusecolumns, std::size(epl16rp8pinfusecolumns), print_epl16rp8_product_terms, config_epl16rp8_pins, nullptr, nullptr}, {"EPL16RP6", 2072, - epl16rp6pinfuserows, ARRAY_LENGTH(epl16rp6pinfuserows), - epl16rp6pinfusecolumns, ARRAY_LENGTH(epl16rp6pinfusecolumns), + epl16rp6pinfuserows, std::size(epl16rp6pinfuserows), + epl16rp6pinfusecolumns, std::size(epl16rp6pinfusecolumns), print_epl16rp6_product_terms, config_epl16rp6_pins, nullptr, nullptr}, {"EPL16RP4", 2072, - epl16rp4pinfuserows, ARRAY_LENGTH(epl16rp4pinfuserows), - epl16rp4pinfusecolumns, ARRAY_LENGTH(epl16rp4pinfusecolumns), + epl16rp4pinfuserows, std::size(epl16rp4pinfuserows), + epl16rp4pinfusecolumns, std::size(epl16rp4pinfusecolumns), print_epl16rp4_product_terms, config_epl16rp4_pins, nullptr, nullptr}, #endif {"PAL10P8", 328, - pal10p8pinfuserows, ARRAY_LENGTH(pal10p8pinfuserows), - pal10p8pinfusecolumns, ARRAY_LENGTH(pal10p8pinfusecolumns), + pal10p8pinfuserows, std::size(pal10p8pinfuserows), + pal10p8pinfusecolumns, std::size(pal10p8pinfusecolumns), print_pal10p8_product_terms, config_pal10p8_pins, nullptr, nullptr}, {"PAL12P6", 390, - pal12p6pinfuserows, ARRAY_LENGTH(pal12p6pinfuserows), - pal12p6pinfusecolumns, ARRAY_LENGTH(pal12p6pinfusecolumns), + pal12p6pinfuserows, std::size(pal12p6pinfuserows), + pal12p6pinfusecolumns, std::size(pal12p6pinfusecolumns), print_pal12p6_product_terms, config_pal12p6_pins, nullptr, nullptr}, {"PAL14P4", 452, - pal14p4pinfuserows, ARRAY_LENGTH(pal14p4pinfuserows), - pal14p4pinfusecolumns, ARRAY_LENGTH(pal14p4pinfusecolumns), + pal14p4pinfuserows, std::size(pal14p4pinfuserows), + pal14p4pinfusecolumns, std::size(pal14p4pinfusecolumns), print_pal14p4_product_terms, config_pal14p4_pins, nullptr, nullptr}, {"PAL16P2", 514, - pal16p2pinfuserows, ARRAY_LENGTH(pal16p2pinfuserows), - pal16p2pinfusecolumns, ARRAY_LENGTH(pal16p2pinfusecolumns), + pal16p2pinfuserows, std::size(pal16p2pinfuserows), + pal16p2pinfusecolumns, std::size(pal16p2pinfusecolumns), print_pal16p2_product_terms, config_pal16p2_pins, nullptr, nullptr}, {"PAL16P8", 2056, - pal16p8pinfuserows, ARRAY_LENGTH(pal16p8pinfuserows), - pal16p8pinfusecolumns, ARRAY_LENGTH(pal16p8pinfusecolumns), + pal16p8pinfuserows, std::size(pal16p8pinfuserows), + pal16p8pinfusecolumns, std::size(pal16p8pinfusecolumns), print_pal16p8_product_terms, config_pal16p8_pins, nullptr, nullptr}, {"PAL16RP4", 2056, - pal16rp4pinfuserows, ARRAY_LENGTH(pal16rp4pinfuserows), - pal16rp4pinfusecolumns, ARRAY_LENGTH(pal16rp4pinfusecolumns), + pal16rp4pinfuserows, std::size(pal16rp4pinfuserows), + pal16rp4pinfusecolumns, std::size(pal16rp4pinfusecolumns), print_pal16rp4_product_terms, config_pal16rp4_pins, nullptr, nullptr}, {"PAL16RP6", 2056, - pal16rp6pinfuserows, ARRAY_LENGTH(pal16rp6pinfuserows), - pal16rp6pinfusecolumns, ARRAY_LENGTH(pal16rp6pinfusecolumns), + pal16rp6pinfuserows, std::size(pal16rp6pinfuserows), + pal16rp6pinfusecolumns, std::size(pal16rp6pinfusecolumns), print_pal16rp6_product_terms, config_pal16rp6_pins, nullptr, nullptr}, {"PAL16RP8", 2056, - pal16rp8pinfuserows, ARRAY_LENGTH(pal16rp8pinfuserows), - pal16rp8pinfusecolumns, ARRAY_LENGTH(pal16rp8pinfusecolumns), + pal16rp8pinfuserows, std::size(pal16rp8pinfuserows), + pal16rp8pinfusecolumns, std::size(pal16rp8pinfusecolumns), print_pal16rp8_product_terms, config_pal16rp8_pins, nullptr, nullptr}, {"PAL6L16", 192, - pal6l16pinfuserows, ARRAY_LENGTH(pal6l16pinfuserows), - pal6l16pinfusecolumns, ARRAY_LENGTH(pal6l16pinfusecolumns), + pal6l16pinfuserows, std::size(pal6l16pinfuserows), + pal6l16pinfusecolumns, std::size(pal6l16pinfusecolumns), print_pal6l16_product_terms, config_pal6l16_pins, nullptr, nullptr}, {"PAL8L14", 224, - pal8l14pinfuserows, ARRAY_LENGTH(pal8l14pinfuserows), - pal8l14pinfusecolumns, ARRAY_LENGTH(pal8l14pinfusecolumns), + pal8l14pinfuserows, std::size(pal8l14pinfuserows), + pal8l14pinfusecolumns, std::size(pal8l14pinfusecolumns), print_pal8l14_product_terms, config_pal8l14_pins, nullptr, nullptr}, {"PAL12H10", 480, - pal12h10pinfuserows, ARRAY_LENGTH(pal12h10pinfuserows), - pal12h10pinfusecolumns, ARRAY_LENGTH(pal12h10pinfusecolumns), + pal12h10pinfuserows, std::size(pal12h10pinfuserows), + pal12h10pinfusecolumns, std::size(pal12h10pinfusecolumns), print_pal12h10_product_terms, config_pal12h10_pins, nullptr, nullptr}, {"PAL12L10", 480, - pal12l10pinfuserows, ARRAY_LENGTH(pal12l10pinfuserows), - pal12l10pinfusecolumns, ARRAY_LENGTH(pal12l10pinfusecolumns), + pal12l10pinfuserows, std::size(pal12l10pinfuserows), + pal12l10pinfusecolumns, std::size(pal12l10pinfusecolumns), print_pal12l10_product_terms, config_pal12l10_pins, nullptr, nullptr}, {"PAL14H8", 560, - pal14h8pinfuserows, ARRAY_LENGTH(pal14h8pinfuserows), - pal14h8pinfusecolumns, ARRAY_LENGTH(pal14h8pinfusecolumns), + pal14h8pinfuserows, std::size(pal14h8pinfuserows), + pal14h8pinfusecolumns, std::size(pal14h8pinfusecolumns), print_pal14h8_product_terms, config_pal14h8_pins, nullptr, nullptr}, {"PAL14L8", 560, - pal14l8pinfuserows, ARRAY_LENGTH(pal14l8pinfuserows), - pal14l8pinfusecolumns, ARRAY_LENGTH(pal14l8pinfusecolumns), + pal14l8pinfuserows, std::size(pal14l8pinfuserows), + pal14l8pinfusecolumns, std::size(pal14l8pinfusecolumns), print_pal14l8_product_terms, config_pal14l8_pins, nullptr, nullptr}, {"PAL16H6", 640, - pal16h6pinfuserows, ARRAY_LENGTH(pal16h6pinfuserows), - pal16h6pinfusecolumns, ARRAY_LENGTH(pal16h6pinfusecolumns), + pal16h6pinfuserows, std::size(pal16h6pinfuserows), + pal16h6pinfusecolumns, std::size(pal16h6pinfusecolumns), print_pal16h6_product_terms, config_pal16h6_pins, nullptr, nullptr}, {"PAL16L6", 640, - pal16l6pinfuserows, ARRAY_LENGTH(pal16l6pinfuserows), - pal16l6pinfusecolumns, ARRAY_LENGTH(pal16l6pinfusecolumns), + pal16l6pinfuserows, std::size(pal16l6pinfuserows), + pal16l6pinfusecolumns, std::size(pal16l6pinfusecolumns), print_pal16l6_product_terms, config_pal16l6_pins, nullptr, nullptr}, {"PAL18H4", 720, - pal18h4pinfuserows, ARRAY_LENGTH(pal18h4pinfuserows), - pal18h4pinfusecolumns, ARRAY_LENGTH(pal18h4pinfusecolumns), + pal18h4pinfuserows, std::size(pal18h4pinfuserows), + pal18h4pinfusecolumns, std::size(pal18h4pinfusecolumns), print_pal18h4_product_terms, config_pal18h4_pins, nullptr, nullptr}, {"PAL18L4", 720, - pal18l4pinfuserows, ARRAY_LENGTH(pal18l4pinfuserows), - pal18l4pinfusecolumns, ARRAY_LENGTH(pal18l4pinfusecolumns), + pal18l4pinfuserows, std::size(pal18l4pinfuserows), + pal18l4pinfusecolumns, std::size(pal18l4pinfusecolumns), print_pal18l4_product_terms, config_pal18l4_pins, nullptr, nullptr}, {"PAL20C1", 640, - pal20c1pinfuserows, ARRAY_LENGTH(pal20c1pinfuserows), - pal20c1pinfusecolumns, ARRAY_LENGTH(pal20c1pinfusecolumns), + pal20c1pinfuserows, std::size(pal20c1pinfuserows), + pal20c1pinfusecolumns, std::size(pal20c1pinfusecolumns), print_pal20c1_product_terms, config_pal20c1_pins, nullptr, nullptr}, {"PAL20L2", 640, - pal20l2pinfuserows, ARRAY_LENGTH(pal20l2pinfuserows), - pal20l2pinfusecolumns, ARRAY_LENGTH(pal20l2pinfusecolumns), + pal20l2pinfuserows, std::size(pal20l2pinfuserows), + pal20l2pinfusecolumns, std::size(pal20l2pinfusecolumns), print_pal20l2_product_terms, config_pal20l2_pins, nullptr, nullptr}, {"82S100", 1928, - _82s100_pls100_pinfuserows, ARRAY_LENGTH(_82s100_pls100_pinfuserows), - _82s100_pls100_pinfusecolumns, ARRAY_LENGTH(_82s100_pls100_pinfusecolumns), + _82s100_pls100_pinfuserows, std::size(_82s100_pls100_pinfuserows), + _82s100_pls100_pinfusecolumns, std::size(_82s100_pls100_pinfusecolumns), print_82s100_pls100_product_terms, config_82s100_pls100_pins, nullptr, nullptr}, {"PLS100", 1928, - _82s100_pls100_pinfuserows, ARRAY_LENGTH(_82s100_pls100_pinfuserows), - _82s100_pls100_pinfusecolumns, ARRAY_LENGTH(_82s100_pls100_pinfusecolumns), + _82s100_pls100_pinfuserows, std::size(_82s100_pls100_pinfuserows), + _82s100_pls100_pinfusecolumns, std::size(_82s100_pls100_pinfusecolumns), print_82s100_pls100_product_terms, config_82s100_pls100_pins, nullptr, nullptr}, {"82S101", 1928, - _82s100_pls100_pinfuserows, ARRAY_LENGTH(_82s100_pls100_pinfuserows), - _82s100_pls100_pinfusecolumns, ARRAY_LENGTH(_82s100_pls100_pinfusecolumns), + _82s100_pls100_pinfuserows, std::size(_82s100_pls100_pinfuserows), + _82s100_pls100_pinfusecolumns, std::size(_82s100_pls100_pinfusecolumns), print_82s100_pls100_product_terms, config_82s100_pls100_pins, nullptr, nullptr}, {"PLS101", 1928, - _82s100_pls100_pinfuserows, ARRAY_LENGTH(_82s100_pls100_pinfuserows), - _82s100_pls100_pinfusecolumns, ARRAY_LENGTH(_82s100_pls100_pinfusecolumns), + _82s100_pls100_pinfuserows, std::size(_82s100_pls100_pinfuserows), + _82s100_pls100_pinfusecolumns, std::size(_82s100_pls100_pinfusecolumns), print_82s100_pls100_product_terms, config_82s100_pls100_pins, nullptr, @@ -2467,19 +2687,17 @@ static int is_pla_file(const char *file) with a pal name -------------------------------------------------*/ -static const pal_data* find_pal_data(const char *name) +static void find_pal_data(const char *name, pal_data_vector& pal_data_vector) { int index; - for (index = 0; index < ARRAY_LENGTH(paldata); ++index) + for (index = 0; index < std::size(paldata); ++index) { if (!core_stricmp(name, paldata[index].name)) { - return &paldata[index]; + pal_data_vector.push_back(&paldata[index]); } } - - return nullptr; } @@ -2781,7 +2999,7 @@ static void generate_product_terms(const pal_data* pal, const jed_data* jed, uin if (!is_output_pin(pin)) { - sprintf(tmpbuffer, LOW_SYMBOL INPUT_SYMBOL "%d", pin); + snprintf(tmpbuffer, 20, LOW_SYMBOL INPUT_SYMBOL "%d", pin); strcat(buffer, tmpbuffer); } else @@ -2792,11 +3010,11 @@ static void generate_product_terms(const pal_data* pal, const jed_data* jed, uin { if (flags & OUTPUT_COMBINATORIAL) { - sprintf(tmpbuffer, LOW_SYMBOL OUTPUT_SYMBOL "%d", pin); + snprintf(tmpbuffer, 20, LOW_SYMBOL OUTPUT_SYMBOL "%d", pin); } else if (flags & OUTPUT_REGISTERED) { - sprintf(tmpbuffer, LOW_SYMBOL REGISTERED_FEEDBACK_OUTPUT_SYMBOL "%d", pin); + snprintf(tmpbuffer, 20, LOW_SYMBOL REGISTERED_FEEDBACK_OUTPUT_SYMBOL "%d", pin); } else { @@ -2807,11 +3025,11 @@ static void generate_product_terms(const pal_data* pal, const jed_data* jed, uin } else if (flags & OUTPUT_FEEDBACK_COMBINATORIAL) { - sprintf(tmpbuffer, LOW_SYMBOL OUTPUT_FEEDBACK_SYMBOL "%d", pin); + snprintf(tmpbuffer, 20, LOW_SYMBOL OUTPUT_FEEDBACK_SYMBOL "%d", pin); } else if (flags & OUTPUT_FEEDBACK_REGISTERED) { - sprintf(tmpbuffer, LOW_SYMBOL REGISTERED_FEEDBACK_SYMBOL "%d", pin); + snprintf(tmpbuffer, 20, LOW_SYMBOL REGISTERED_FEEDBACK_SYMBOL "%d", pin); } else { @@ -2835,7 +3053,7 @@ static void generate_product_terms(const pal_data* pal, const jed_data* jed, uin if (!is_output_pin(pin)) { - sprintf(tmpbuffer, INPUT_SYMBOL "%d", pin); + snprintf(tmpbuffer, 20, INPUT_SYMBOL "%d", pin); strcat(buffer, tmpbuffer); } else @@ -2846,11 +3064,11 @@ static void generate_product_terms(const pal_data* pal, const jed_data* jed, uin { if (flags & OUTPUT_COMBINATORIAL) { - sprintf(tmpbuffer, OUTPUT_SYMBOL "%d", pin); + snprintf(tmpbuffer, 20, OUTPUT_SYMBOL "%d", pin); } else if (flags & OUTPUT_REGISTERED) { - sprintf(tmpbuffer, REGISTERED_FEEDBACK_OUTPUT_SYMBOL "%d", pin); + snprintf(tmpbuffer, 20, REGISTERED_FEEDBACK_OUTPUT_SYMBOL "%d", pin); } else { @@ -2861,11 +3079,11 @@ static void generate_product_terms(const pal_data* pal, const jed_data* jed, uin } else if (flags & OUTPUT_FEEDBACK_COMBINATORIAL) { - sprintf(tmpbuffer, OUTPUT_FEEDBACK_SYMBOL "%d", pin); + snprintf(tmpbuffer, 20, OUTPUT_FEEDBACK_SYMBOL "%d", pin); } else if (flags & OUTPUT_FEEDBACK_REGISTERED) { - sprintf(tmpbuffer, REGISTERED_FEEDBACK_SYMBOL "%d", pin); + snprintf(tmpbuffer, 20, REGISTERED_FEEDBACK_SYMBOL "%d", pin); } else { @@ -3014,11 +3232,11 @@ static void print_product_terms(const pal_data* pal, const jed_data* jed) if (flags & OUTPUT_COMBINATORIAL) { - sprintf(buffer, OUTPUT_SYMBOL "%d " COMBINATORIAL_ASSIGNMENT " ", outputpins[index].pin); + snprintf(buffer, 200, OUTPUT_SYMBOL "%d " COMBINATORIAL_ASSIGNMENT " ", outputpins[index].pin); } else if (flags & OUTPUT_REGISTERED) { - sprintf(buffer, REGISTERED_FEEDBACK_SYMBOL "%d " REGISTERED_ASSIGNMENT " ", outputpins[index].pin); + snprintf(buffer, 200, REGISTERED_FEEDBACK_SYMBOL "%d " REGISTERED_ASSIGNMENT " ", outputpins[index].pin); } else { @@ -3113,74 +3331,6 @@ static void print_product_terms(const pal_data* pal, const jed_data* jed) /*------------------------------------------------- - config_palce16v8_pin_as_7_product_terms_and_oe_term - configures - the fuse rows of a PALCE16V8 pin with seven - product terms and one output enable product term. --------------------------------------------------*/ - -static void config_palce16v8_pin_as_7_product_terms_and_oe_term(uint16_t pin) -{ - static pin_fuse_rows pinfuserows[] = { - {12, 1792, 1824, 2016}, - {13, 1536, 1568, 1760}, - {14, 1280, 1312, 1504}, - {15, 1024, 1056, 1248}, - {16, 768, 800, 992}, - {17, 512, 544, 736}, - {18, 256, 288, 480}, - {19, 0, 32, 224}}; - uint16_t index; - - for (index = 0; index < ARRAY_LENGTH(pinfuserows); ++index) - { - if (pinfuserows[index].pin == pin) - { - palce16v8pinfuserows[index].fuserowoutputenable = pinfuserows[index].fuserowoutputenable; - palce16v8pinfuserows[index].fuserowtermstart = pinfuserows[index].fuserowtermstart; - palce16v8pinfuserows[index].fuserowtermend = pinfuserows[index].fuserowtermend; - - break; - } - } -} - - - -/*------------------------------------------------- - config_palce16v8_pin_as_8_product_terms - configures - the fuse rows of a PALCE16V8 pin with eight - product terms and no output enable product term. --------------------------------------------------*/ - -static void config_palce16v8_pin_as_8_product_terms(uint16_t pin) -{ - static pin_fuse_rows pinfuserows[] = { - {12, NO_OUTPUT_ENABLE_FUSE_ROW, 1792, 2016}, - {13, NO_OUTPUT_ENABLE_FUSE_ROW, 1536, 1760}, - {14, NO_OUTPUT_ENABLE_FUSE_ROW, 1280, 1504}, - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 1024, 1248}, - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 768, 992}, - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 512, 736}, - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 256, 480}, - {19, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 224}}; - uint16_t index; - - for (index = 0; index < ARRAY_LENGTH(pinfuserows); ++index) - { - if (pinfuserows[index].pin == pin) - { - palce16v8pinfuserows[index].fuserowoutputenable = pinfuserows[index].fuserowoutputenable; - palce16v8pinfuserows[index].fuserowtermstart = pinfuserows[index].fuserowtermstart; - palce16v8pinfuserows[index].fuserowtermend = pinfuserows[index].fuserowtermend; - - break; - } - } -} - - - -/*------------------------------------------------- print_pal20xxx_product_terms - prints the product terms for a PAL20X4, PAL20X8 and PAL20X10 -------------------------------------------------*/ @@ -3207,7 +3357,7 @@ static void print_pal20xxx_product_terms(const pal_data* pal, const jed_data* je if (flags & OUTPUT_COMBINATORIAL) { - sprintf(buffer, LOW_SYMBOL OUTPUT_SYMBOL "%d " COMBINATORIAL_ASSIGNMENT " ", outputpins[index].pin); + snprintf(buffer, 200, LOW_SYMBOL OUTPUT_SYMBOL "%d " COMBINATORIAL_ASSIGNMENT " ", outputpins[index].pin); printf("%s", buffer); @@ -3262,7 +3412,7 @@ static void print_pal20xxx_product_terms(const pal_data* pal, const jed_data* je } else if (flags & OUTPUT_REGISTERED) { - sprintf(buffer, LOW_SYMBOL REGISTERED_FEEDBACK_SYMBOL "%d " REGISTERED_ASSIGNMENT " ", outputpins[index].pin); + snprintf(buffer, 200, LOW_SYMBOL REGISTERED_FEEDBACK_SYMBOL "%d " REGISTERED_ASSIGNMENT " ", outputpins[index].pin); printf("%s", buffer); @@ -3495,18 +3645,6 @@ static void print_pal16r8_product_terms(const pal_data* pal, const jed_data* jed /*------------------------------------------------- - print_palce16v8_product_terms - prints the product - terms for a PALCE16V8 --------------------------------------------------*/ - -static void print_palce16v8_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- print_gal16v8_product_terms - prints the product terms for a GAL16V8 -------------------------------------------------*/ @@ -3576,13 +3714,13 @@ static void print_gal18v10_product_terms(const pal_data* pal, const jed_data* je print_product_terms(pal, jed); - /* Synchronous Reset */ + /* Synchronous Preset */ generate_product_terms(pal, jed, 3420, buffer); if (strlen(buffer)) { - printf("Synchronous Reset:\n\n"); + printf("Synchronous Preset:\n\n"); printf("%s\n", buffer); printf("\n"); } @@ -3710,6 +3848,129 @@ static void print_pal20x10_product_terms(const pal_data* pal, const jed_data* je /*------------------------------------------------- + print_gal20v8_product_terms - prints the product + terms for a GAL20V8 +-------------------------------------------------*/ + +static void print_gal20v8_product_terms(const pal_data* pal, const jed_data* jed) +{ + print_product_terms(pal, jed); +} + + + +/*------------------------------------------------- + print_palce22v10_pal22v10_product_terms - prints the product + terms for a PALCE22V10 and PAL22V10 +-------------------------------------------------*/ + +static void print_palce22v10_pal22v10_product_terms(const pal_data* pal, const jed_data* jed) +{ + char buffer[200]; + + print_product_terms(pal, jed); + + /* Synchronous Preset */ + + generate_product_terms(pal, jed, 5764, buffer); + + if (strlen(buffer)) + { + printf("Synchronous Preset:\n\n"); + printf("%s\n", buffer); + printf("\n"); + } + + /* Asynchronous Reset */ + + generate_product_terms(pal, jed, 0, buffer); + + if (strlen(buffer)) + { + printf("Asynchronous Reset:\n\n"); + printf("%s\n", buffer); + printf("\n"); + } +} + + + +/*------------------------------------------------- + print_gal22v10_product_terms - prints the product + terms for a GAL22V10 +-------------------------------------------------*/ + +static void print_gal22v10_product_terms(const pal_data* pal, const jed_data* jed) +{ + char buffer[200]; + + print_product_terms(pal, jed); + + /* Synchronous Preset */ + + generate_product_terms(pal, jed, 5764, buffer); + + if (strlen(buffer)) + { + printf("Synchronous Preset:\n\n"); + printf("%s\n", buffer); + printf("\n"); + } + + /* Asynchronous Reset */ + + generate_product_terms(pal, jed, 0, buffer); + + if (strlen(buffer)) + { + printf("Asynchronous Reset:\n\n"); + printf("%s\n", buffer); + printf("\n"); + } +} + +/*------------------------------------------------- + print_atf22v10_power_down_mode_product_terms - prints the product + terms for a ATF22V10 configured in power-down mode +-------------------------------------------------*/ + +static void print_atf22v10_power_down_mode_product_terms(const pal_data* pal, const jed_data* jed) +{ + char buffer[200]; + + print_product_terms(pal, jed); + + /* Synchronous Preset */ + + generate_product_terms(pal, jed, 5764, buffer); + + if (strlen(buffer)) + { + printf("Synchronous Preset:\n\n"); + printf("%s\n", buffer); + printf("\n"); + } + + /* Asynchronous Reset */ + + generate_product_terms(pal, jed, 0, buffer); + + if (strlen(buffer)) + { + printf("Asynchronous Reset:\n\n"); + printf("%s\n", buffer); + printf("\n"); + } + + /* Pin 4 (DIP/SOIC package) and Pin 5 (PLCC package) controls power down mode */ + + printf("Pin 4 (DIP/SOIC package) and Pin 5 (PLCC package) Controls Power Down Mode\n\n"); + printf("\n"); +} + + + +/*------------------------------------------------- print_82s153_pls153_product_terms - prints the product terms for a 82S153/PLS153 -------------------------------------------------*/ @@ -3741,7 +4002,7 @@ static void print_82s153_pls153_product_terms(const pal_data* pal, const jed_dat indent += strlen(LOW_SYMBOL); } - sprintf(buffer, OUTPUT_SYMBOL "%d " COMBINATORIAL_ASSIGNMENT " ", outputpins[index].pin); + snprintf(buffer, 200, OUTPUT_SYMBOL "%d " COMBINATORIAL_ASSIGNMENT " ", outputpins[index].pin); printf("%s", buffer); @@ -3844,7 +4105,7 @@ static void print_ck2605_product_terms(const pal_data* pal, const jed_data* jed) indent += strlen(LOW_SYMBOL); } - sprintf(buffer, OUTPUT_SYMBOL "%d " COMBINATORIAL_ASSIGNMENT " ", outputpins[index].pin); + snprintf(buffer, 200, OUTPUT_SYMBOL "%d " COMBINATORIAL_ASSIGNMENT " ", outputpins[index].pin); printf("%s", buffer); @@ -3954,7 +4215,7 @@ static void print_epl10p8_product_terms(const pal_data* pal, const jed_data* jed printf("Equations:\n\n"); - for (index = 0; index < ARRAY_LENGTH(memory_cells); ++index) + for (index = 0; index < std::size(memory_cells); ++index) { flags = outputpins[index].flags; @@ -3967,7 +4228,7 @@ static void print_epl10p8_product_terms(const pal_data* pal, const jed_data* jed indent += strlen(LOW_SYMBOL); } - sprintf(buffer, OUTPUT_SYMBOL "%d " COMBINATORIAL_ASSIGNMENT " ", outputpins[index].pin); + snprintf(buffer, 200, OUTPUT_SYMBOL "%d " COMBINATORIAL_ASSIGNMENT " ", outputpins[index].pin); printf("%s", buffer); @@ -4426,7 +4687,7 @@ static void print_82s100_pls100_product_terms(const pal_data* pal, const jed_dat indent += strlen(LOW_SYMBOL); } - sprintf(buffer, OUTPUT_SYMBOL "%d " COMBINATORIAL_ASSIGNMENT " ", outputpins[index].pin); + snprintf(buffer, 200, OUTPUT_SYMBOL "%d " COMBINATORIAL_ASSIGNMENT " ", outputpins[index].pin); printf("%s", buffer); @@ -4504,8 +4765,8 @@ static void config_pal10l8_pins(const pal_data* pal, const jed_data* jed) {18, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, {19, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -4528,8 +4789,8 @@ static void config_pal10h8_pins(const pal_data* pal, const jed_data* jed) {18, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, {19, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -4550,8 +4811,8 @@ static void config_pal12l6_pins(const pal_data* pal, const jed_data* jed) {17, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, {18, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -4572,8 +4833,8 @@ static void config_pal12h6_pins(const pal_data* pal, const jed_data* jed) {17, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, {18, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -4592,8 +4853,8 @@ static void config_pal14l4_pins(const pal_data* pal, const jed_data* jed) {16, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, {17, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -4612,8 +4873,8 @@ static void config_pal14h4_pins(const pal_data* pal, const jed_data* jed) {16, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, {17, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -4630,8 +4891,8 @@ static void config_pal16l2_pins(const pal_data* pal, const jed_data* jed) {15, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, {16, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -4648,8 +4909,8 @@ static void config_pal16h2_pins(const pal_data* pal, const jed_data* jed) {15, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, {16, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -4666,8 +4927,8 @@ static void config_pal16c1_pins(const pal_data* pal, const jed_data* jed) {15, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, {16, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -4696,7 +4957,7 @@ static void config_pal16l8_pins(const pal_data* pal, const jed_data* jed) } } - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); + set_input_pins(input_pins, std::size(input_pins)); set_output_pins(output_pins, output_pin_count); } @@ -4732,7 +4993,7 @@ static void config_pal16r4_pins(const pal_data* pal, const jed_data* jed) ++output_pin_count; } - for (index = 0; index < ARRAY_LENGTH(registered_pins); ++index) + for (index = 0; index < std::size(registered_pins); ++index) { output_pins[output_pin_count].pin = registered_pins[index]; output_pins[output_pin_count].flags = OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED; @@ -4756,7 +5017,7 @@ static void config_pal16r4_pins(const pal_data* pal, const jed_data* jed) ++output_pin_count; } - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); + set_input_pins(input_pins, std::size(input_pins)); set_output_pins(output_pins, output_pin_count); } @@ -4784,7 +5045,7 @@ static void config_pal16r6_pins(const pal_data* pal, const jed_data* jed) ++output_pin_count; } - for (index = 0; index < ARRAY_LENGTH(registered_pins); ++index) + for (index = 0; index < std::size(registered_pins); ++index) { output_pins[output_pin_count].pin = registered_pins[index]; output_pins[output_pin_count].flags = OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED; @@ -4800,7 +5061,7 @@ static void config_pal16r6_pins(const pal_data* pal, const jed_data* jed) ++output_pin_count; } - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); + set_input_pins(input_pins, std::size(input_pins)); set_output_pins(output_pins, output_pin_count); } @@ -4824,274 +5085,8 @@ static void config_pal16r8_pins(const pal_data* pal, const jed_data* jed) {18, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, {19, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}}; - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); -} - - - -/*------------------------------------------------- - config_palce16v8_pins - configures the pins for - a PALCE16V8 --------------------------------------------------*/ - -static void config_palce16v8_pins(const pal_data* pal, const jed_data* jed) -{ - typedef struct _output_logic_macrocell output_logic_macrocell; - struct _output_logic_macrocell - { - uint16_t pin; - uint16_t sl0_fuse; /* registers allowed (0 - registered, 1 - not registered) */ - uint16_t sl1_fuse; /* output polarity (0 - low, 1 - high) */ - uint16_t fuserowoutputenable; - }; - - static output_logic_macrocell macrocells[] = { - {12, 2127, 2055, 1792}, - {13, 2126, 2054, 1536}, - {14, 2125, 2053, 1280}, - {15, 2124, 2052, 1024}, - {16, 2123, 2051, 768}, - {17, 2122, 2050, 512}, - {18, 2121, 2049, 256}, - {19, 2120, 2048, 0}}; - static pin_fuse_columns pinfusecolumns_i_or_o[] = { - {1, 3, 2}, - {2, 1, 0}, - {3, 5, 4}, - {4, 9, 8}, - {5, 13, 12}, - {6, 17, 16}, - {7, 21, 20}, - {8, 25, 24}, - {9, 29, 28}, - {11, 31, 30}, - {12, 27, 26}, - {13, 23, 22}, - {14, 19, 18}, - {17, 15, 14}, - {18, 11, 10}, - {19, 7, 6}}; - static pin_fuse_columns pinfusecolumns_io[] = { - {1, 3, 2}, - {2, 1, 0}, - {3, 5, 4}, - {4, 9, 8}, - {5, 13, 12}, - {6, 17, 16}, - {7, 21, 20}, - {8, 25, 24}, - {9, 29, 28}, - {11, 31, 30}, - {13, 27, 26}, - {14, 23, 22}, - {15, 19, 18}, - {16, 15, 14}, - {17, 11, 10}, - {18, 7, 6}}; - static pin_fuse_columns pinfusecolumns_regs[] = { - {2, 1, 0}, - {3, 5, 4}, - {4, 9, 8}, - {5, 13, 12}, - {6, 17, 16}, - {7, 21, 20}, - {8, 25, 24}, - {9, 29, 28}, - {12, 31, 30}, - {13, 27, 26}, - {14, 23, 22}, - {15, 19, 18}, - {16, 15, 14}, - {17, 11, 10}, - {18, 7, 6}, - {19, 3, 2}}; - static uint16_t input_pins_i_or_o[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11}; - static uint16_t input_pins_io[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11}; - static uint16_t input_pins_regs[] = {2, 3, 4, 5, 6, 7, 8, 9}; - static uint16_t sg0 = 2192; - static uint16_t sg1 = 2193; - uint16_t input_pins[18]; - pin_output_config output_pins[ARRAY_LENGTH(macrocells)]; - uint16_t index, input_pin_count, output_pin_count; - - input_pin_count = 0; - output_pin_count = 0; - - if (!jed_get_fuse(jed, sg0)) - { - /* Device uses registers */ - - if (jed_get_fuse(jed, sg1)) - { - memcpy(palce16v8pinfusecolumns, pinfusecolumns_regs, sizeof(pinfusecolumns_regs)); - - memcpy(input_pins, input_pins_regs, sizeof(input_pins_regs)); - - input_pin_count = ARRAY_LENGTH(input_pins_regs); - - for (index = 0; index < ARRAY_LENGTH(macrocells); ++index) - { - if (!jed_get_fuse(jed, macrocells[index].sl0_fuse)) - { - /* Registered output */ - - config_palce16v8_pin_as_8_product_terms(macrocells[index].pin); - - output_pins[output_pin_count].pin = macrocells[index].pin; - output_pins[output_pin_count].flags = OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED; - - if (!jed_get_fuse(jed, macrocells[index].sl1_fuse)) - { - output_pins[output_pin_count].flags |= OUTPUT_ACTIVELOW; - } - else - { - output_pins[output_pin_count].flags |= OUTPUT_ACTIVEHIGH; - } - - ++output_pin_count; - - input_pins[input_pin_count] = macrocells[index].pin; - - ++input_pin_count; - } - else - { - /* Combinatorial I/O */ - - if (does_output_enable_fuse_row_allow_output(pal, jed, macrocells[index].fuserowoutputenable)) - { - config_palce16v8_pin_as_7_product_terms_and_oe_term(macrocells[index].pin); - - output_pins[output_pin_count].pin = macrocells[index].pin; - output_pins[output_pin_count].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; - - if (!jed_get_fuse(jed, macrocells[index].sl1_fuse)) - { - output_pins[output_pin_count].flags |= OUTPUT_ACTIVELOW; - } - else - { - output_pins[output_pin_count].flags |= OUTPUT_ACTIVEHIGH; - } - - ++output_pin_count; - } - - input_pins[input_pin_count] = macrocells[index].pin; - - ++input_pin_count; - } - } - } - else - { - fprintf(stderr, "Unknown configuration type!\n"); - } - } - else - { - /* Device uses no registers */ - - if (jed_get_fuse(jed, sg1)) - { - /* Combinatorial I/O (7 product terms and 1 output enable product term) */ - - memcpy(palce16v8pinfusecolumns, pinfusecolumns_io, sizeof(pinfusecolumns_io)); - - memcpy(input_pins, input_pins_io, sizeof(input_pins_io)); - - input_pin_count = ARRAY_LENGTH(input_pins_io); - - for (index = 0; index < ARRAY_LENGTH(macrocells); ++index) - { - if (does_output_enable_fuse_row_allow_output(pal, jed, macrocells[index].fuserowoutputenable)) - { - config_palce16v8_pin_as_7_product_terms_and_oe_term(macrocells[index].pin); - - output_pins[output_pin_count].pin = macrocells[index].pin; - output_pins[output_pin_count].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; - - if (!jed_get_fuse(jed, macrocells[index].sl1_fuse)) - { - output_pins[output_pin_count].flags |= OUTPUT_ACTIVELOW; - } - else - { - output_pins[output_pin_count].flags |= OUTPUT_ACTIVEHIGH; - } - - ++output_pin_count; - } - - /* Pins 12 and 19 cannot be used as an input only an output. */ - - if (macrocells[index].pin != 12 && macrocells[index].pin != 19) - { - input_pins[input_pin_count] = macrocells[index].pin; - - ++input_pin_count; - } - } - } - else - { - /* Combinatorial Output or Input */ - - memcpy(palce16v8pinfusecolumns, pinfusecolumns_i_or_o, sizeof(pinfusecolumns_i_or_o)); - - memcpy(input_pins, input_pins_i_or_o, sizeof(input_pins_i_or_o)); - - input_pin_count = ARRAY_LENGTH(input_pins_i_or_o); - - for (index = 0; index < ARRAY_LENGTH(macrocells); ++index) - { - if (!jed_get_fuse(jed, macrocells[index].sl0_fuse)) - { - /* pin configured as an output only */ - - config_palce16v8_pin_as_8_product_terms(macrocells[index].pin); - - output_pins[output_pin_count].pin = macrocells[index].pin; - output_pins[output_pin_count].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE; - - if (!jed_get_fuse(jed, macrocells[index].sl1_fuse)) - { - output_pins[output_pin_count].flags |= OUTPUT_ACTIVELOW; - } - else - { - output_pins[output_pin_count].flags |= OUTPUT_ACTIVEHIGH; - } - - ++output_pin_count; - } - else - { - /* pin configured as an input only */ - - input_pins[input_pin_count] = macrocells[index].pin; - - ++input_pin_count; - } - } - } - } - - set_input_pins(input_pins, input_pin_count); - set_output_pins(output_pins, output_pin_count); - - /* 2056 - 2119 are the 64 bit signature fuses */ - - /* 2128 - 2135 product term 8? */ - /* 2136 - 2143 product term 7? */ - /* 2144 - 2151 product term 6? */ - /* 2152 - 2159 product term 5? */ - /* 2160 - 2167 product term 4? */ - /* 2168 - 2175 product term 3? */ - /* 2176 - 2183 product term 2? */ - /* 2184 - 2191 product term 1? */ + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -5129,7 +5124,7 @@ static void config_gal16v8_pins(const pal_data* pal, const jed_data* jed) {17, NO_OUTPUT_ENABLE_FUSE_ROW, 512, 736}, {18, NO_OUTPUT_ENABLE_FUSE_ROW, 256, 480}, {19, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 224}}; - static pin_fuse_rows pinfuserows_combinatorial[] = { + static pin_fuse_rows pinfuserows_combinatorialcomplex[] = { {12, 1792, 1824, 2016}, {13, 1536, 1568, 1760}, {14, 1280, 1312, 1504}, @@ -5138,6 +5133,15 @@ static void config_gal16v8_pins(const pal_data* pal, const jed_data* jed) {17, 512, 544, 736}, {18, 256, 288, 480}, {19, 0, 32, 224}}; + static pin_fuse_rows pinfuserows_combinatorialsimple[] = { + {12, NO_OUTPUT_ENABLE_FUSE_ROW, 1792, 2016}, + {13, NO_OUTPUT_ENABLE_FUSE_ROW, 1536, 1760}, + {14, NO_OUTPUT_ENABLE_FUSE_ROW, 1280, 1504}, + {15, NO_OUTPUT_ENABLE_FUSE_ROW, 1024, 1248}, + {16, NO_OUTPUT_ENABLE_FUSE_ROW, 768, 992}, + {17, NO_OUTPUT_ENABLE_FUSE_ROW, 512, 736}, + {18, NO_OUTPUT_ENABLE_FUSE_ROW, 256, 480}, + {19, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 224}}; static pin_fuse_columns pinfusecolumns_registered[] = { {2, 1, 0}, {3, 5, 4}, @@ -5191,9 +5195,9 @@ static void config_gal16v8_pins(const pal_data* pal, const jed_data* jed) {19, 7, 6}}; static uint16_t input_pins_registered[] = {2, 3, 4, 5, 6, 7, 8, 9, 12, 13, 14, 15, 16, 17, 18, 19}; static uint16_t input_pins_combinatorialcomplex[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 14, 15, 16, 17, 18}; - static uint16_t input_pins_combinatorialsimple[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 17, 18, 19}; - pin_output_config output_pins[ARRAY_LENGTH(macrocells)]; - uint16_t index, output_pin_count; + uint16_t input_pins_combinatorialsimple[18]; + pin_output_config output_pins[std::size(macrocells)]; + uint16_t index, input_pin_count, output_pin_count; output_pin_count = 0; @@ -5208,12 +5212,12 @@ static void config_gal16v8_pins(const pal_data* pal, const jed_data* jed) { /* Complex Mode */ - set_input_pins(input_pins_combinatorialcomplex, ARRAY_LENGTH(input_pins_combinatorialcomplex)); + set_input_pins(input_pins_combinatorialcomplex, std::size(input_pins_combinatorialcomplex)); - memcpy(gal16v8pinfuserows, pinfuserows_combinatorial, sizeof(pinfuserows_combinatorial)); + memcpy(gal16v8pinfuserows, pinfuserows_combinatorialcomplex, sizeof(pinfuserows_combinatorialcomplex)); memcpy(gal16v8pinfusecolumns, pinfusecolumns_combinatorialcomplex, sizeof(pinfusecolumns_combinatorialcomplex)); - for (index = 0; index < ARRAY_LENGTH(macrocells); ++index) + for (index = 0; index < std::size(macrocells); ++index) { if (is_gal16v8_product_term_enabled(pal, jed, pal->pinfuserows[index].fuserowoutputenable) && does_output_enable_fuse_row_allow_output(pal, jed, pal->pinfuserows[index].fuserowoutputenable)) @@ -5248,25 +5252,64 @@ static void config_gal16v8_pins(const pal_data* pal, const jed_data* jed) { /* Simple Mode */ - set_input_pins(input_pins_combinatorialsimple, ARRAY_LENGTH(input_pins_combinatorialsimple)); + input_pin_count = 0; - memcpy(gal16v8pinfuserows, pinfuserows_registered, sizeof(pinfuserows_registered)); + for (index = 1; index < 10; ++index) + { + input_pins_combinatorialsimple[input_pin_count] = index; + + ++input_pin_count; + } + + input_pins_combinatorialsimple[input_pin_count] = 11; + + ++input_pin_count; + + memcpy(gal16v8pinfuserows, pinfuserows_combinatorialsimple, sizeof(pinfuserows_combinatorialsimple)); memcpy(gal16v8pinfusecolumns, pinfusecolumns_combinatorialsimple, sizeof(pinfusecolumns_combinatorialsimple)); - for (index = 0; index < ARRAY_LENGTH(macrocells); ++index) + for (index = 0; index < std::size(macrocells); ++index) { - if (jed_get_fuse(jed, macrocells[index].ac1_fuse)) + if (macrocells[index].pin != 15 && macrocells[index].pin != 16) { - /* Pin is for input only */ + if (jed_get_fuse(jed, macrocells[index].ac1_fuse)) + { + /* Pin is for input only */ + + input_pins_combinatorialsimple[input_pin_count] = macrocells[index].pin; - if (macrocells[index].pin == 15 || macrocells[index].pin == 16) + ++input_pin_count; + } + else { - fprintf(stderr, "Pin %d cannot be configured as an input pin.\n", - macrocells[index].pin); + output_pins[output_pin_count].pin = macrocells[index].pin; + output_pins[output_pin_count].flags = OUTPUT_COMBINATORIAL; + + if (jed_get_fuse(jed, macrocells[index].xor_fuse)) + { + output_pins[output_pin_count].flags |= OUTPUT_ACTIVEHIGH; + } + else + { + output_pins[output_pin_count].flags |= OUTPUT_ACTIVELOW; + } + + output_pins[output_pin_count].flags |= OUTPUT_FEEDBACK_OUTPUT; + + input_pins_combinatorialsimple[input_pin_count] = macrocells[index].pin; + + ++input_pin_count; + + ++output_pin_count; } } else { + /* For pins 15 and 16 ignore the value of the ac1_fuse (This + normally determine if the pin is an input or output.) because + according to the datasheet these macrocells are output + only when in simple mode. */ + output_pins[output_pin_count].pin = macrocells[index].pin; output_pins[output_pin_count].flags = OUTPUT_COMBINATORIAL; @@ -5279,38 +5322,32 @@ static void config_gal16v8_pins(const pal_data* pal, const jed_data* jed) output_pins[output_pin_count].flags |= OUTPUT_ACTIVELOW; } - if (output_pins[output_pin_count].pin != 15 && - output_pins[output_pin_count].pin != 16) - { - output_pins[output_pin_count].flags |= OUTPUT_FEEDBACK_OUTPUT; - } - else - { - output_pins[output_pin_count].flags |= OUTPUT_FEEDBACK_NONE; - } + output_pins[output_pin_count].flags |= OUTPUT_FEEDBACK_NONE; ++output_pin_count; } } + + set_input_pins(input_pins_combinatorialsimple, input_pin_count); } } else { /* Registered */ - set_input_pins(input_pins_registered, ARRAY_LENGTH(input_pins_registered)); + set_input_pins(input_pins_registered, std::size(input_pins_registered)); memcpy(gal16v8pinfusecolumns, pinfusecolumns_registered, sizeof(pinfusecolumns_registered)); - for (index = 0; index < ARRAY_LENGTH(macrocells); ++index) + for (index = 0; index < std::size(macrocells); ++index) { if (jed_get_fuse(jed, macrocells[index].ac1_fuse)) { /* combinatorial pin */ - gal16v8pinfuserows[index].fuserowoutputenable = pinfuserows_combinatorial[index].fuserowoutputenable; - gal16v8pinfuserows[index].fuserowtermstart = pinfuserows_combinatorial[index].fuserowtermstart; - gal16v8pinfuserows[index].fuserowtermend = pinfuserows_combinatorial[index].fuserowtermend; + gal16v8pinfuserows[index].fuserowoutputenable = pinfuserows_combinatorialcomplex[index].fuserowoutputenable; + gal16v8pinfuserows[index].fuserowtermstart = pinfuserows_combinatorialcomplex[index].fuserowtermstart; + gal16v8pinfuserows[index].fuserowtermend = pinfuserows_combinatorialcomplex[index].fuserowtermend; if (is_gal16v8_product_term_enabled(pal, jed, pal->pinfuserows[index].fuserowoutputenable) && does_output_enable_fuse_row_allow_output(pal, jed, pal->pinfuserows[index].fuserowoutputenable)) @@ -5387,14 +5424,14 @@ static void config_peel18cv8_pins(const pal_data* pal, const jed_data* jed) {18, 2668, 2669, 2670, 2671}, {19, 2664, 2665, 2666, 2667}}; static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19}; - pin_output_config output_pins[ARRAY_LENGTH(macrocells)]; + pin_output_config output_pins[std::size(macrocells)]; uint16_t index, output_pin_count; - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); + set_input_pins(input_pins, std::size(input_pins)); output_pin_count = 0; - for (index = 0; index < ARRAY_LENGTH(macrocells); ++index) + for (index = 0; index < std::size(macrocells); ++index) { if (jed_get_fuse(jed, macrocells[index].feedback1_fuse) && !jed_get_fuse(jed, macrocells[index].feedback2_fuse)) @@ -5509,7 +5546,7 @@ static void config_ampal18p8_pins(const pal_data* pal, const jed_data* jed) pin_output_config output_pins[8]; uint16_t index, output_pin_count; - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); + set_input_pins(input_pins, std::size(input_pins)); output_pin_count = 0; @@ -5565,12 +5602,12 @@ static void config_gal18v10_pins(const pal_data* pal, const jed_data* jed) {18, 3458, 3459}, {19, 3456, 3457}}; static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19}; - pin_output_config output_pins[ARRAY_LENGTH(macrocells)]; + pin_output_config output_pins[std::size(macrocells)]; uint16_t index, output_pin_count; output_pin_count = 0; - for (index = 0; index < ARRAY_LENGTH(output_pins); ++index) + for (index = 0; index < std::size(output_pins); ++index) { if (jed_get_fuse(jed, macrocells[index].s1_fuse)) { @@ -5613,7 +5650,7 @@ static void config_gal18v10_pins(const pal_data* pal, const jed_data* jed) } } - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); + set_input_pins(input_pins, std::size(input_pins)); set_output_pins(output_pins, output_pin_count); } @@ -5653,7 +5690,7 @@ static void config_pal20l8_pins(const pal_data* pal, const jed_data* jed) } } - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); + set_input_pins(input_pins, std::size(input_pins)); set_output_pins(output_pins, output_pin_count); } @@ -5693,7 +5730,7 @@ static void config_pal20l10_pins(const pal_data* pal, const jed_data* jed) } } - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); + set_input_pins(input_pins, std::size(input_pins)); set_output_pins(output_pins, output_pin_count); } @@ -5729,7 +5766,7 @@ static void config_pal20r4_pins(const pal_data* pal, const jed_data* jed) ++output_pin_count; } - for (index = 0; index < ARRAY_LENGTH(registered_pins); ++index) + for (index = 0; index < std::size(registered_pins); ++index) { output_pins[output_pin_count].pin = registered_pins[index]; output_pins[output_pin_count].flags = OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED; @@ -5753,7 +5790,7 @@ static void config_pal20r4_pins(const pal_data* pal, const jed_data* jed) ++output_pin_count; } - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); + set_input_pins(input_pins, std::size(input_pins)); set_output_pins(output_pins, output_pin_count); } @@ -5781,7 +5818,7 @@ static void config_pal20r6_pins(const pal_data* pal, const jed_data* jed) ++output_pin_count; } - for (index = 0; index < ARRAY_LENGTH(registered_pins); ++index) + for (index = 0; index < std::size(registered_pins); ++index) { output_pins[output_pin_count].pin = registered_pins[index]; output_pins[output_pin_count].flags = OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED; @@ -5797,7 +5834,7 @@ static void config_pal20r6_pins(const pal_data* pal, const jed_data* jed) ++output_pin_count; } - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); + set_input_pins(input_pins, std::size(input_pins)); set_output_pins(output_pins, output_pin_count); } @@ -5821,8 +5858,8 @@ static void config_pal20r8_pins(const pal_data* pal, const jed_data* jed) {21, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, {22, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}}; - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -5847,8 +5884,8 @@ static void config_pal20ra10_pins(const pal_data* pal, const jed_data* jed) {22, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, {23, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}}; - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -5873,12 +5910,12 @@ static void config_pal20x4_pins(const pal_data* pal, const jed_data* jed) {22, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT}, {23, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT}}; - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } /*------------------------------------------------- - config_pal20x10_pins - configures the pins for + config_pal20x8_pins - configures the pins for a PAL20X8 -------------------------------------------------*/ @@ -5897,8 +5934,8 @@ static void config_pal20x8_pins(const pal_data* pal, const jed_data* jed) {22, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, {23, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT}}; - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -5923,8 +5960,568 @@ static void config_pal20x10_pins(const pal_data* pal, const jed_data* jed) {22, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, {23, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}}; - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); +} + + + +/*------------------------------------------------- + config_gal20v8_pins - configures the pins for + a GAL20V8 +-------------------------------------------------*/ + +static void config_gal20v8_pins(const pal_data* pal, const jed_data* jed) +{ + typedef struct _output_logic_macrocell output_logic_macrocell; + struct _output_logic_macrocell + { + uint16_t pin; + uint16_t xor_fuse; + uint16_t ac1_fuse; + }; + + static output_logic_macrocell macrocells[] = { + {15, 2567, 2639}, + {16, 2566, 2638}, + {17, 2565, 2637}, + {18, 2564, 2636}, + {19, 2563, 2635}, + {20, 2562, 2634}, + {21, 2561, 2633}, + {22, 2560, 2632}}; + static pin_fuse_rows pinfuserows_registered[] = { + {15, NO_OUTPUT_ENABLE_FUSE_ROW, 2240, 2520}, + {16, NO_OUTPUT_ENABLE_FUSE_ROW, 1920, 2200}, + {17, NO_OUTPUT_ENABLE_FUSE_ROW, 1600, 1880}, + {18, NO_OUTPUT_ENABLE_FUSE_ROW, 1280, 1560}, + {19, NO_OUTPUT_ENABLE_FUSE_ROW, 960, 1240}, + {20, NO_OUTPUT_ENABLE_FUSE_ROW, 640, 920}, + {21, NO_OUTPUT_ENABLE_FUSE_ROW, 320, 600}, + {22, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 280}}; + static pin_fuse_rows pinfuserows_combinatorialcomplex[] = { + {15, 2240, 2280, 2520}, + {16, 1920, 1960, 2200}, + {17, 1600, 1640, 1880}, + {18, 1280, 1320, 1560}, + {19, 960, 1000, 1240}, + {20, 640, 680, 920}, + {21, 320, 360, 600}, + {22, 0, 40, 280}}; + static pin_fuse_rows pinfuserows_combinatorialsimple[] = { + {15, NO_OUTPUT_ENABLE_FUSE_ROW, 2240, 2520}, + {16, NO_OUTPUT_ENABLE_FUSE_ROW, 1920, 2200}, + {17, NO_OUTPUT_ENABLE_FUSE_ROW, 1600, 1880}, + {18, NO_OUTPUT_ENABLE_FUSE_ROW, 1280, 1560}, + {19, NO_OUTPUT_ENABLE_FUSE_ROW, 960, 1240}, + {20, NO_OUTPUT_ENABLE_FUSE_ROW, 640, 920}, + {21, NO_OUTPUT_ENABLE_FUSE_ROW, 320, 600}, + {22, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 280}}; + static pin_fuse_columns pinfusecolumns_registered[] = { + {2, 1, 0}, + {3, 5, 4}, + {4, 9, 8}, + {5, 13, 12}, + {6, 17, 16}, + {7, 21, 20}, + {8, 25, 24}, + {9, 29, 28}, + {10, 33, 32}, + {11, 37, 36}, + {14, 39, 38}, + {15, 35, 34}, + {16, 31, 30}, + {17, 27, 26}, + {18, 23, 22}, + {19, 19, 18}, + {20, 15, 14}, + {21, 11, 10}, + {22, 7, 6}, + {23, 3, 2}}; + static pin_fuse_columns pinfusecolumns_combinatorialcomplex[] = { + {1, 3, 2}, + {2, 1, 0}, + {3, 5, 4}, + {4, 9, 8}, + {5, 13, 12}, + {6, 17, 16}, + {7, 21, 20}, + {8, 25, 24}, + {9, 29, 28}, + {10, 33, 32}, + {11, 37, 36}, + {13, 39, 38}, + {14, 35, 34}, + {16, 31, 30}, + {17, 27, 26}, + {18, 23, 22}, + {19, 19, 18}, + {20, 15, 14}, + {21, 11, 10}, + {23, 7, 6}}; + static pin_fuse_columns pinfusecolumns_combinatorialsimple[] = { + {1, 3, 2}, + {2, 1, 0}, + {3, 5, 4}, + {4, 9, 8}, + {5, 13, 12}, + {6, 17, 16}, + {7, 21, 20}, + {8, 25, 24}, + {9, 29, 28}, + {10, 33, 32}, + {11, 37, 36}, + {13, 39, 38}, + {14, 35, 34}, + {15, 31, 30}, + {16, 27, 26}, + {17, 23, 22}, + {20, 19, 18}, + {21, 15, 14}, + {22, 11, 10}, + {23, 7, 6}}; + static uint16_t input_pins_registered[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; + static uint16_t input_pins_combinatorialcomplex[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 16, 17, 18, 19, 20, 21, 23}; + uint16_t input_pins_combinatorialsimple[22]; + pin_output_config output_pins[std::size(macrocells)]; + uint16_t index, input_pin_count, output_pin_count; + + output_pin_count = 0; + + /* SYN Fuse: 0 - registered, 1 - combinatorial */ + + if (jed_get_fuse(jed, 2704)) + { + /* Combinatorial */ + /* AC0 Fuse: 0 - simple mode, 1 - complex mode */ + + if (jed_get_fuse(jed, 2705)) + { + /* Complex Mode */ + + set_input_pins(input_pins_combinatorialcomplex, std::size(input_pins_combinatorialcomplex)); + + memcpy(gal20v8pinfuserows, pinfuserows_combinatorialcomplex, sizeof(pinfuserows_combinatorialcomplex)); + memcpy(gal20v8pinfusecolumns, pinfusecolumns_combinatorialcomplex, sizeof(pinfusecolumns_combinatorialcomplex)); + + for (index = 0; index < std::size(macrocells); ++index) + { + if (is_gal20v8_product_term_enabled(pal, jed, pal->pinfuserows[index].fuserowoutputenable) && + does_output_enable_fuse_row_allow_output(pal, jed, pal->pinfuserows[index].fuserowoutputenable)) + { + output_pins[output_pin_count].pin = macrocells[index].pin; + output_pins[output_pin_count].flags = OUTPUT_COMBINATORIAL; + + if (jed_get_fuse(jed, macrocells[index].xor_fuse)) + { + output_pins[output_pin_count].flags |= OUTPUT_ACTIVEHIGH; + } + else + { + output_pins[output_pin_count].flags |= OUTPUT_ACTIVELOW; + } + + if (output_pins[output_pin_count].pin != 15 && + output_pins[output_pin_count].pin != 22) + { + output_pins[output_pin_count].flags |= OUTPUT_FEEDBACK_OUTPUT; + } + else + { + output_pins[output_pin_count].flags |= OUTPUT_FEEDBACK_NONE; + } + + ++output_pin_count; + } + } + } + else + { + /* Simple Mode */ + + input_pin_count = 0; + + for (index = 1; index < 12; ++index) + { + input_pins_combinatorialsimple[input_pin_count] = index; + + ++input_pin_count; + } + + for (index = 13; index < 15; ++index) + { + input_pins_combinatorialsimple[input_pin_count] = index; + + ++input_pin_count; + } + + memcpy(gal20v8pinfuserows, pinfuserows_combinatorialsimple, sizeof(pinfuserows_combinatorialsimple)); + memcpy(gal20v8pinfusecolumns, pinfusecolumns_combinatorialsimple, sizeof(pinfusecolumns_combinatorialsimple)); + + for (index = 0; index < std::size(macrocells); ++index) + { + if (jed_get_fuse(jed, macrocells[index].ac1_fuse)) + { + /* Pin is for input only */ + + input_pins_combinatorialsimple[input_pin_count] = macrocells[index].pin; + + ++input_pin_count; + + if (macrocells[index].pin == 18 || macrocells[index].pin == 19) + { + fprintf(stderr, "Pin %d cannot be configured as an input pin.\n", + macrocells[index].pin); + } + } + else + { + output_pins[output_pin_count].pin = macrocells[index].pin; + output_pins[output_pin_count].flags = OUTPUT_COMBINATORIAL; + + if (jed_get_fuse(jed, macrocells[index].xor_fuse)) + { + output_pins[output_pin_count].flags |= OUTPUT_ACTIVEHIGH; + } + else + { + output_pins[output_pin_count].flags |= OUTPUT_ACTIVELOW; + } + + if (macrocells[index].pin != 18 && macrocells[index].pin != 19) + { + output_pins[output_pin_count].flags |= OUTPUT_FEEDBACK_OUTPUT; + + input_pins_combinatorialsimple[input_pin_count] = macrocells[index].pin; + + ++input_pin_count; + } + else + { + output_pins[output_pin_count].flags |= OUTPUT_FEEDBACK_NONE; + } + + ++output_pin_count; + } + } + + input_pins_combinatorialsimple[input_pin_count] = 23; + + ++input_pin_count; + + set_input_pins(input_pins_combinatorialsimple, input_pin_count); + } + } + else + { + /* Registered */ + + set_input_pins(input_pins_registered, std::size(input_pins_registered)); + + memcpy(gal20v8pinfusecolumns, pinfusecolumns_registered, sizeof(pinfusecolumns_registered)); + + for (index = 0; index < std::size(macrocells); ++index) + { + if (jed_get_fuse(jed, macrocells[index].ac1_fuse)) + { + /* combinatorial pin */ + + gal20v8pinfuserows[index].fuserowoutputenable = pinfuserows_combinatorialcomplex[index].fuserowoutputenable; + gal20v8pinfuserows[index].fuserowtermstart = pinfuserows_combinatorialcomplex[index].fuserowtermstart; + gal20v8pinfuserows[index].fuserowtermend = pinfuserows_combinatorialcomplex[index].fuserowtermend; + + if (is_gal20v8_product_term_enabled(pal, jed, pal->pinfuserows[index].fuserowoutputenable) && + does_output_enable_fuse_row_allow_output(pal, jed, pal->pinfuserows[index].fuserowoutputenable)) + { + output_pins[output_pin_count].pin = macrocells[index].pin; + output_pins[output_pin_count].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; + + if (jed_get_fuse(jed, macrocells[index].xor_fuse)) + { + output_pins[output_pin_count].flags |= OUTPUT_ACTIVEHIGH; + } + else + { + output_pins[output_pin_count].flags |= OUTPUT_ACTIVELOW; + } + + ++output_pin_count; + } + } + else + { + /* registered pin */ + + gal20v8pinfuserows[index].fuserowoutputenable = pinfuserows_registered[index].fuserowoutputenable; + gal20v8pinfuserows[index].fuserowtermstart = pinfuserows_registered[index].fuserowtermstart; + gal20v8pinfuserows[index].fuserowtermend = pinfuserows_registered[index].fuserowtermend; + + output_pins[output_pin_count].pin = macrocells[index].pin; + output_pins[output_pin_count].flags = OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED; + + if (jed_get_fuse(jed, macrocells[index].xor_fuse)) + { + output_pins[output_pin_count].flags |= OUTPUT_ACTIVEHIGH; + } + else + { + output_pins[output_pin_count].flags |= OUTPUT_ACTIVELOW; + } + + ++output_pin_count; + } + } + } + + set_output_pins(output_pins, output_pin_count); +} + + + +/*------------------------------------------------- + config_palce22v10_pal22v10_pins - configures the pins for + a PALCE22V10 +-------------------------------------------------*/ + +static void config_palce22v10_pal22v10_pins(const pal_data* pal, const jed_data* jed) +{ + typedef struct _output_logic_macrocell output_logic_macrocell; + struct _output_logic_macrocell + { + uint16_t pin; + uint16_t s0_fuse; /* output polarity (0 - low, 1 - high) */ + uint16_t s1_fuse; /* registers allowed (0 - registered, 1 - not registered) */ + }; + + static output_logic_macrocell macrocells[] = { + {14, 5826, 5827}, + {15, 5824, 5825}, + {16, 5822, 5823}, + {17, 5820, 5821}, + {18, 5818, 5819}, + {19, 5816, 5817}, + {20, 5814, 5815}, + {21, 5812, 5813}, + {22, 5810, 5811}, + {23, 5808, 5809}}; + static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; + pin_output_config output_pins[std::size(macrocells)]; + uint16_t index, output_pin_count; + + output_pin_count = 0; + + for (index = 0; index < std::size(output_pins); ++index) + { + if (jed_get_fuse(jed, macrocells[index].s1_fuse)) + { + /* Combinatorial output or dedicated input */ + + if (does_output_enable_fuse_row_allow_output(pal, jed, pal->pinfuserows[index].fuserowoutputenable)) + { + output_pins[output_pin_count].pin = macrocells[index].pin; + output_pins[output_pin_count].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; + + if (!jed_get_fuse(jed, macrocells[index].s0_fuse)) + { + output_pins[output_pin_count].flags |= OUTPUT_ACTIVELOW; + } + else + { + output_pins[output_pin_count].flags |= OUTPUT_ACTIVEHIGH; + } + + ++output_pin_count; + } + } + else + { + /* Registered output */ + + output_pins[output_pin_count].pin = macrocells[index].pin; + output_pins[output_pin_count].flags = OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED; + + if (!jed_get_fuse(jed, macrocells[index].s0_fuse)) + { + output_pins[output_pin_count].flags |= OUTPUT_ACTIVELOW; + } + else + { + output_pins[output_pin_count].flags |= OUTPUT_ACTIVEHIGH; + } + + ++output_pin_count; + } + } + + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, output_pin_count); +} + + + +/*------------------------------------------------- + config_gal22v10_pins - configures the pins for + a GAL22V10 +-------------------------------------------------*/ + +static void config_gal22v10_pins(const pal_data* pal, const jed_data* jed) +{ + typedef struct _output_logic_macrocell output_logic_macrocell; + struct _output_logic_macrocell + { + uint16_t pin; + uint16_t s0_fuse; /* 0 - active low, 1 - active high */ + uint16_t s1_fuse; /* 0 - registered, 1 - combinatorial */ + }; + + static output_logic_macrocell macrocells[] = { + {14, 5826, 5827}, + {15, 5824, 5825}, + {16, 5822, 5823}, + {17, 5820, 5821}, + {18, 5818, 5819}, + {19, 5816, 5817}, + {20, 5814, 5815}, + {21, 5812, 5813}, + {22, 5810, 5811}, + {23, 5808, 5809}}; + static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; + pin_output_config output_pins[std::size(macrocells)]; + uint16_t index, output_pin_count; + + output_pin_count = 0; + + for (index = 0; index < std::size(output_pins); ++index) + { + if (jed_get_fuse(jed, macrocells[index].s1_fuse)) + { + /* Combinatorial output or dedicated input */ + + if (does_output_enable_fuse_row_allow_output(pal, jed, pal->pinfuserows[index].fuserowoutputenable)) + { + output_pins[output_pin_count].pin = macrocells[index].pin; + output_pins[output_pin_count].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; + + if (!jed_get_fuse(jed, macrocells[index].s0_fuse)) + { + output_pins[output_pin_count].flags |= OUTPUT_ACTIVELOW; + } + else + { + output_pins[output_pin_count].flags |= OUTPUT_ACTIVEHIGH; + } + + ++output_pin_count; + } + } + else + { + /* Registered output */ + + output_pins[output_pin_count].pin = macrocells[index].pin; + output_pins[output_pin_count].flags = OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED; + + if (!jed_get_fuse(jed, macrocells[index].s0_fuse)) + { + output_pins[output_pin_count].flags |= OUTPUT_ACTIVELOW; + } + else + { + output_pins[output_pin_count].flags |= OUTPUT_ACTIVEHIGH; + } + + ++output_pin_count; + } + } + + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, output_pin_count); +} + + + +/*------------------------------------------------- + config_atf22v10_power_down_mode_pins - configures the pins for + a ATF22V10 configured in power down mode. +-------------------------------------------------*/ + +static void config_atf22v10_power_down_mode_pins(const pal_data* pal, const jed_data* jed) +{ + typedef struct _output_logic_macrocell output_logic_macrocell; + struct _output_logic_macrocell + { + uint16_t pin; + uint16_t s0_fuse; /* 0 - active low, 1 - active high */ + uint16_t s1_fuse; /* 0 - registered, 1 - combinatorial */ + }; + + static output_logic_macrocell macrocells[] = { + {14, 5826, 5827}, + {15, 5824, 5825}, + {16, 5822, 5823}, + {17, 5820, 5821}, + {18, 5818, 5819}, + {19, 5816, 5817}, + {20, 5814, 5815}, + {21, 5812, 5813}, + {22, 5810, 5811}, + {23, 5808, 5809}}; + static uint16_t input_pins[] = {1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; + pin_output_config output_pins[std::size(macrocells)]; + uint16_t index, output_pin_count; + + output_pin_count = 0; + + if (jed_get_fuse(jed, 5893)) + { + fprintf(stderr, "Warning: Power down fuse not blown!\n"); + } + + for (index = 0; index < std::size(output_pins); ++index) + { + if (jed_get_fuse(jed, macrocells[index].s1_fuse)) + { + /* Combinatorial output or dedicated input */ + + if (does_output_enable_fuse_row_allow_output(pal, jed, pal->pinfuserows[index].fuserowoutputenable)) + { + output_pins[output_pin_count].pin = macrocells[index].pin; + output_pins[output_pin_count].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; + + if (!jed_get_fuse(jed, macrocells[index].s0_fuse)) + { + output_pins[output_pin_count].flags |= OUTPUT_ACTIVELOW; + } + else + { + output_pins[output_pin_count].flags |= OUTPUT_ACTIVEHIGH; + } + + ++output_pin_count; + } + } + else + { + /* Registered output */ + + output_pins[output_pin_count].pin = macrocells[index].pin; + output_pins[output_pin_count].flags = OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED; + + if (!jed_get_fuse(jed, macrocells[index].s0_fuse)) + { + output_pins[output_pin_count].flags |= OUTPUT_ACTIVELOW; + } + else + { + output_pins[output_pin_count].flags |= OUTPUT_ACTIVEHIGH; + } + + ++output_pin_count; + } + } + + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, output_pin_count); } @@ -5962,7 +6559,7 @@ static void config_82s153_pls153_pins(const pal_data* pal, const jed_data* jed) } } - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); + set_input_pins(input_pins, std::size(input_pins)); set_output_pins(output_pins, output_pin_count); } @@ -6001,7 +6598,7 @@ static void config_ck2605_pins(const pal_data* pal, const jed_data* jed) } } - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); + set_input_pins(input_pins, std::size(input_pins)); set_output_pins(output_pins, output_pin_count); } @@ -6035,7 +6632,7 @@ static void config_epl10p8_pins(const pal_data* pal, const jed_data* jed) pin_output_config output_pins[8]; uint16_t index; - for (index = 0; index < ARRAY_LENGTH(memory_cells); ++index) + for (index = 0; index < std::size(memory_cells); ++index) { output_pins[index].pin = memory_cells[index].pin; output_pins[index].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE; @@ -6050,8 +6647,8 @@ static void config_epl10p8_pins(const pal_data* pal, const jed_data* jed) } } - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -6083,7 +6680,7 @@ static void config_epl12p6_pins(const pal_data* pal, const jed_data* jed) pin_output_config output_pins[8]; uint16_t index; - for (index = 0; index < ARRAY_LENGTH(memory_cells); ++index) + for (index = 0; index < std::size(memory_cells); ++index) { output_pins[index].pin = memory_cells[index].pin; output_pins[index].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE; @@ -6098,8 +6695,8 @@ static void config_epl12p6_pins(const pal_data* pal, const jed_data* jed) } } - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -6129,7 +6726,7 @@ static void config_epl14p4_pins(const pal_data* pal, const jed_data* jed) pin_output_config output_pins[8]; uint16_t index; - for (index = 0; index < ARRAY_LENGTH(memory_cells); ++index) + for (index = 0; index < std::size(memory_cells); ++index) { output_pins[index].pin = memory_cells[index].pin; output_pins[index].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE; @@ -6144,8 +6741,8 @@ static void config_epl14p4_pins(const pal_data* pal, const jed_data* jed) } } - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -6173,7 +6770,7 @@ static void config_epl16p2_pins(const pal_data* pal, const jed_data* jed) pin_output_config output_pins[8]; uint16_t index; - for (index = 0; index < ARRAY_LENGTH(memory_cells); ++index) + for (index = 0; index < std::size(memory_cells); ++index) { output_pins[index].pin = memory_cells[index].pin; output_pins[index].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE; @@ -6188,8 +6785,8 @@ static void config_epl16p2_pins(const pal_data* pal, const jed_data* jed) } } - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -6223,7 +6820,7 @@ static void config_epl16p8_pins(const pal_data* pal, const jed_data* jed) pin_output_config output_pins[8]; uint16_t index; - for (index = 0; index < ARRAY_LENGTH(memory_cells); ++index) + for (index = 0; index < std::size(memory_cells); ++index) { output_pins[index].pin = memory_cells[index].pin; output_pins[index].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE; @@ -6238,8 +6835,8 @@ static void config_epl16p8_pins(const pal_data* pal, const jed_data* jed) } } - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -6273,7 +6870,7 @@ static void config_epl16rp8_pins(const pal_data* pal, const jed_data* jed) pin_output_config output_pins[8]; uint16_t index; - for (index = 0; index < ARRAY_LENGTH(memory_cells); ++index) + for (index = 0; index < std::size(memory_cells); ++index) { output_pins[index].pin = memory_cells[index].pin; output_pins[index].flags = OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED; @@ -6288,8 +6885,8 @@ static void config_epl16rp8_pins(const pal_data* pal, const jed_data* jed) } } - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -6323,7 +6920,7 @@ static void config_epl16rp6_pins(const pal_data* pal, const jed_data* jed) pin_output_config output_pins[8]; uint16_t index; - for (index = 0; index < ARRAY_LENGTH(memory_cells); ++index) + for (index = 0; index < std::size(memory_cells); ++index) { output_pins[index].pin = memory_cells[index].pin; @@ -6348,8 +6945,8 @@ static void config_epl16rp6_pins(const pal_data* pal, const jed_data* jed) } } - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -6383,7 +6980,7 @@ static void config_epl16rp4_pins(const pal_data* pal, const jed_data* jed) pin_output_config output_pins[8]; uint16_t index; - for (index = 0; index < ARRAY_LENGTH(memory_cells); ++index) + for (index = 0; index < std::size(memory_cells); ++index) { output_pins[index].pin = memory_cells[index].pin; @@ -6407,8 +7004,8 @@ static void config_epl16rp4_pins(const pal_data* pal, const jed_data* jed) } } - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } #endif @@ -6425,7 +7022,7 @@ static void config_pal10p8_pins(const pal_data* pal, const jed_data* jed) pin_output_config output_pins[8]; uint16_t index; - for (index = 0; index < ARRAY_LENGTH(output_pins); ++index) + for (index = 0; index < std::size(output_pins); ++index) { output_pins[index].pin = index + 12; output_pins[index].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE; @@ -6440,8 +7037,8 @@ static void config_pal10p8_pins(const pal_data* pal, const jed_data* jed) } } - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -6457,7 +7054,7 @@ static void config_pal12p6_pins(const pal_data* pal, const jed_data* jed) pin_output_config output_pins[6]; uint16_t index; - for (index = 0; index < ARRAY_LENGTH(output_pins); ++index) + for (index = 0; index < std::size(output_pins); ++index) { output_pins[index].pin = index + 13; output_pins[index].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE; @@ -6472,8 +7069,8 @@ static void config_pal12p6_pins(const pal_data* pal, const jed_data* jed) } } - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -6489,7 +7086,7 @@ static void config_pal14p4_pins(const pal_data* pal, const jed_data* jed) pin_output_config output_pins[4]; uint16_t index; - for (index = 0; index < ARRAY_LENGTH(output_pins); ++index) + for (index = 0; index < std::size(output_pins); ++index) { output_pins[index].pin = index + 14; output_pins[index].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE; @@ -6504,8 +7101,8 @@ static void config_pal14p4_pins(const pal_data* pal, const jed_data* jed) } } - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -6521,7 +7118,7 @@ static void config_pal16p2_pins(const pal_data* pal, const jed_data* jed) pin_output_config output_pins[2]; uint16_t index; - for (index = 0; index < ARRAY_LENGTH(output_pins); ++index) + for (index = 0; index < std::size(output_pins); ++index) { output_pins[index].pin = index + 15; output_pins[index].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE; @@ -6536,8 +7133,8 @@ static void config_pal16p2_pins(const pal_data* pal, const jed_data* jed) } } - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -6575,7 +7172,7 @@ static void config_pal16p8_pins(const pal_data* pal, const jed_data* jed) } } - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); + set_input_pins(input_pins, std::size(input_pins)); set_output_pins(output_pins, output_pin_count); } @@ -6629,7 +7226,7 @@ static void config_pal16rp4_pins(const pal_data* pal, const jed_data* jed) ++output_pin_count; } - for (index = 0; index < ARRAY_LENGTH(registered_pins); ++index) + for (index = 0; index < std::size(registered_pins); ++index) { output_pins[output_pin_count].pin = registered_pins[index]; output_pins[output_pin_count].flags = OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED; @@ -6680,7 +7277,7 @@ static void config_pal16rp4_pins(const pal_data* pal, const jed_data* jed) ++output_pin_count; } - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); + set_input_pins(input_pins, std::size(input_pins)); set_output_pins(output_pins, output_pin_count); } @@ -6717,7 +7314,7 @@ static void config_pal16rp6_pins(const pal_data* pal, const jed_data* jed) ++output_pin_count; } - for (index = 0; index < ARRAY_LENGTH(registered_pins); ++index) + for (index = 0; index < std::size(registered_pins); ++index) { output_pins[output_pin_count].pin = registered_pins[index]; output_pins[output_pin_count].flags = OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED; @@ -6751,7 +7348,7 @@ static void config_pal16rp6_pins(const pal_data* pal, const jed_data* jed) ++output_pin_count; } - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); + set_input_pins(input_pins, std::size(input_pins)); set_output_pins(output_pins, output_pin_count); } @@ -6776,7 +7373,7 @@ static void config_pal16rp8_pins(const pal_data* pal, const jed_data* jed) {19, OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}}; uint16_t index; - for (index = 0; index < ARRAY_LENGTH(output_pins); ++index) + for (index = 0; index < std::size(output_pins); ++index) { if (!jed_get_fuse(jed, 2055 - index)) { @@ -6788,8 +7385,8 @@ static void config_pal16rp8_pins(const pal_data* pal, const jed_data* jed) } } - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -6820,8 +7417,8 @@ static void config_pal6l16_pins(const pal_data* pal, const jed_data* jed) {22, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, {23, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -6850,8 +7447,8 @@ static void config_pal8l14_pins(const pal_data* pal, const jed_data* jed) {22, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, {23, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -6876,8 +7473,8 @@ static void config_pal12h10_pins(const pal_data* pal, const jed_data* jed) {22, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, {23, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -6902,8 +7499,8 @@ static void config_pal12l10_pins(const pal_data* pal, const jed_data* jed) {22, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, {23, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -6926,8 +7523,8 @@ static void config_pal14h8_pins(const pal_data* pal, const jed_data* jed) {21, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, {22, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -6950,8 +7547,8 @@ static void config_pal14l8_pins(const pal_data* pal, const jed_data* jed) {21, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, {22, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -6972,8 +7569,8 @@ static void config_pal16h6_pins(const pal_data* pal, const jed_data* jed) {20, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, {21, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -6994,8 +7591,8 @@ static void config_pal16l6_pins(const pal_data* pal, const jed_data* jed) {20, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, {21, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -7014,8 +7611,8 @@ static void config_pal18h4_pins(const pal_data* pal, const jed_data* jed) {19, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, {20, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -7034,8 +7631,8 @@ static void config_pal18l4_pins(const pal_data* pal, const jed_data* jed) {19, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, {20, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -7052,8 +7649,8 @@ static void config_pal20c1_pins(const pal_data* pal, const jed_data* jed) {18, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, {19, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -7070,8 +7667,8 @@ static void config_pal20l2_pins(const pal_data* pal, const jed_data* jed) {18, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, {19, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -7086,7 +7683,7 @@ static void config_82s100_pls100_pins(const pal_data* pal, const jed_data* jed) static uint16_t input_pins[] = {9, 8, 7, 6, 5, 4, 3, 2, 27, 26, 25, 24, 23, 22, 21, 20}; pin_output_config output_pins[8]; - for (uint16_t index = 0; index < ARRAY_LENGTH(output_pins); ++index) + for (uint16_t index = 0; index < std::size(output_pins); ++index) { output_pins[index].pin = pal->pinfuserows[index].pin; output_pins[index].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE; @@ -7101,8 +7698,8 @@ static void config_82s100_pls100_pins(const pal_data* pal, const jed_data* jed) } } - set_input_pins(input_pins, ARRAY_LENGTH(input_pins)); - set_output_pins(output_pins, ARRAY_LENGTH(output_pins)); + set_input_pins(input_pins, std::size(input_pins)); + set_output_pins(output_pins, std::size(output_pins)); } @@ -7131,6 +7728,29 @@ static int is_gal16v8_product_term_enabled(const pal_data* pal, const jed_data* /*------------------------------------------------- + is_gal20v8_product_term_enabled - determines if + a fuse row in a GAL20V8 is enabled +-------------------------------------------------*/ + +static int is_gal20v8_product_term_enabled(const pal_data* pal, const jed_data* jed, uint16_t fuserow) +{ + uint16_t fuse_ptd; + + fuse_ptd = (fuserow / calc_fuse_column_count(pal)) + 2640; + + if (fuse_ptd > 2703) + { + fprintf(stderr, "Fuse row %d is illegal!\n", fuserow); + + return 0; + } + + return jed_get_fuse(jed, fuse_ptd); +} + + + +/*------------------------------------------------- get_peel18cv8_pin_fuse_state - determines the fuse state of an input pin in a fuse row -------------------------------------------------*/ @@ -7228,53 +7848,6 @@ static uint16_t get_peel18cv8_pin_fuse_state(const pal_data* pal, const jed_data /*------------------------------------------------- - read_source_file - read a raw source file - into an allocated memory buffer --------------------------------------------------*/ - -static int read_source_file(const char *srcfile) -{ - size_t bytes; - FILE *file; - - /* open the source file */ - file = fopen(srcfile, "rb"); - if (!file) - { - fprintf(stderr, "Unable to open source file '%s'!\n", srcfile); - return 1; - } - - /* allocate memory for the data */ - fseek(file, 0, SEEK_END); - srcbuflen = ftell(file); - fseek(file, 0, SEEK_SET); - srcbuf = (uint8_t *)malloc(srcbuflen); - if (!srcbuf) - { - fprintf(stderr, "Unable to allocate %d bytes for the source!\n", (int)srcbuflen); - fclose(file); - return 1; - } - - /* read the data */ - bytes = fread(srcbuf, 1, srcbuflen, file); - if (bytes != srcbuflen) - { - fprintf(stderr, "Error reading %d bytes from the source!\n", (int)srcbuflen); - free(srcbuf); - fclose(file); - return 1; - } - - /* close up shop */ - fclose(file); - return 0; -} - - - -/*------------------------------------------------- write_dest_file - write a memory buffer raw into a desintation file -------------------------------------------------*/ @@ -7323,6 +7896,8 @@ static int print_usage() " jedutil -view <source.jed> <device> -- dump JED logic equations\n" " jedutil -view <source.bin> <device> -- dump binary logic equations\n" " jedutil -viewlist -- view list of supported devices\n" + " jedutil -listcompatible <source.jed> -- list compatible devices\n" + " jedutil -listcompatible <source.bin> -- list compatible devices\n" ); return 0; @@ -7340,7 +7915,6 @@ static int command_convert(int argc, char *argv[]) int src_is_jed, src_is_pla, dst_is_jed; int numfuses = 0; jed_data jed; - int err; if (argc < 2) { @@ -7375,10 +7949,10 @@ static int command_convert(int argc, char *argv[]) } /* read the source file */ - err = read_source_file(srcfile); - if (err != 0) + auto src = util::stdio_read(fopen(srcfile, "rb")); + if (!src) { - free(srcbuf); + fprintf(stderr, "Unable to open source file '%s'!\n", srcfile); return 1; } @@ -7390,16 +7964,18 @@ static int command_convert(int argc, char *argv[]) printf("Converting '%s' to binary form '%s'\n", srcfile, dstfile); /* read the fuse data */ + int err; if (src_is_jed) - err = jed_parse(srcbuf, srcbuflen, &jed); - else if (src_is_pla) - err = pla_parse(srcbuf, srcbuflen, &jed); + err = jed_parse(*src, &jed); + else /* if (src_is_pla) */ + err = pla_parse(*src, &jed); + src.reset(); switch (err) { - case JEDERR_INVALID_DATA: fprintf(stderr, "Fatal error: Invalid source file\n"); free(srcbuf); return 1; - case JEDERR_BAD_XMIT_SUM: fprintf(stderr, "Fatal error: Bad transmission checksum\n"); free(srcbuf); return 1; - case JEDERR_BAD_FUSE_SUM: fprintf(stderr, "Fatal error: Bad fusemap checksum\n"); free(srcbuf); return 1; + case JEDERR_INVALID_DATA: fprintf(stderr, "Fatal error: Invalid source file\n"); return 1; + case JEDERR_BAD_XMIT_SUM: fprintf(stderr, "Fatal error: Bad transmission checksum\n"); return 1; + case JEDERR_BAD_FUSE_SUM: fprintf(stderr, "Fatal error: Bad fusemap checksum\n"); return 1; } /* override the number of fuses */ @@ -7416,7 +7992,6 @@ static int command_convert(int argc, char *argv[]) if (!dstbuf) { fprintf(stderr, "Unable to allocate %d bytes for the target buffer!\n", (int)dstbuflen); - free(srcbuf); return 1; } dstbuflen = jedbin_output(&jed, dstbuf, dstbuflen); @@ -7428,10 +8003,12 @@ static int command_convert(int argc, char *argv[]) printf("Converting '%s' to JED form '%s'\n", srcfile, dstfile); /* read the binary data */ - err = jedbin_parse(srcbuf, srcbuflen, &jed); + int err = jedbin_parse(*src, &jed); + src.reset(); + switch (err) { - case JEDERR_INVALID_DATA: fprintf(stderr, "Fatal error: Invalid binary JEDEC file\n"); free(srcbuf); return 1; + case JEDERR_INVALID_DATA: fprintf(stderr, "Fatal error: Invalid binary JEDEC file\n"); return 1; } /* print out data */ @@ -7444,15 +8021,13 @@ static int command_convert(int argc, char *argv[]) if (!dstbuf) { fprintf(stderr, "Unable to allocate %d bytes for the target buffer!\n", (int)dstbuflen); - free(srcbuf); return 1; } dstbuflen = jed_output(&jed, dstbuf, dstbuflen); } /* write the destination file */ - err = write_dest_file(dstfile); - free(srcbuf); + int err = write_dest_file(dstfile); if (err != 0) return 1; @@ -7472,6 +8047,7 @@ static int command_view(int argc, char *argv[]) int result = 0; const char *srcfile, *palname; int is_jed; + pal_data_vector pal_data_vector; const pal_data* pal; jed_data jed; int err; @@ -7489,18 +8065,19 @@ static int command_view(int argc, char *argv[]) is_jed = is_jed_file(srcfile); /* find the pal entry */ - pal = find_pal_data(palname); - if (!pal) + find_pal_data(palname, pal_data_vector); + + if (pal_data_vector.size() == 0) { fprintf(stderr, "Unknown pal name.\n"); return 1; } /* read the source file */ - err = read_source_file(srcfile); - if (err != 0) + auto src = util::stdio_read(fopen(srcfile, "rb")); + if (!src) { - result = 1; + fprintf(stderr, "Unable to open source file '%s'!\n", srcfile); goto end; } @@ -7508,7 +8085,8 @@ static int command_view(int argc, char *argv[]) if (is_jed) { /* read the JEDEC data */ - err = jed_parse(srcbuf, srcbuflen, &jed); + err = jed_parse(*src, &jed); + src.reset(); switch (err) { case JEDERR_INVALID_DATA: fprintf(stderr, "Fatal error: Invalid .JED file\n"); result = 1; goto end; @@ -7519,14 +8097,25 @@ static int command_view(int argc, char *argv[]) else { /* read the binary data */ - err = jedbin_parse(srcbuf, srcbuflen, &jed); + err = jedbin_parse(*src, &jed); + src.reset(); switch (err) { case JEDERR_INVALID_DATA: fprintf(stderr, "Fatal error: Invalid binary JEDEC file\n"); result = 1; goto end; } } - if (jed.numfuses != pal->numfuses) + pal = nullptr; + + for (pal_data_vector::iterator it = pal_data_vector.begin(); pal == nullptr && it != pal_data_vector.end(); ++it) + { + if (jed.numfuses == (*it)->numfuses) + { + pal = *it; + } + } + + if (pal == nullptr) { fprintf(stderr, "Fuse count does not match this pal type."); result = 1; @@ -7548,7 +8137,6 @@ static int command_view(int argc, char *argv[]) } end: - free(srcbuf); return result; } @@ -7561,6 +8149,9 @@ end: static int command_viewlist(int argc, char *argv[]) { + typedef std::set<std::string> string_set; + + string_set nameset; int index; if (argc > 0) @@ -7568,15 +8159,92 @@ static int command_viewlist(int argc, char *argv[]) return print_usage(); } - for (index = 0; index < ARRAY_LENGTH(paldata); ++index) + for (index = 0; index < std::size(paldata); ++index) + { + nameset.insert(paldata[index].name); + } + + for (string_set::iterator it = nameset.begin(); it != nameset.end(); ++it) { - printf("%s\n", paldata[index].name); + printf("%s\n", (*it).c_str()); } return 0; } + +/*------------------------------------------------- + command_listcompatible - views the list of + compatible devices +-------------------------------------------------*/ + +static int command_listcompatible(int argc, char *argv[]) +{ + int result = 0; + const char *srcfile; + int is_jed; + jed_data jed; + int err; + int index; + + if (argc != 1) + { + return print_usage(); + } + + /* extract arguments */ + srcfile = argv[0]; + + /* does the source end in '.jed'? */ + is_jed = is_jed_file(srcfile); + + /* read the source file */ + auto src = util::stdio_read(fopen(srcfile, "rb")); + if (!src) + { + fprintf(stderr, "Unable to open source file '%s'!\n", srcfile); + goto end; + } + + /* if the source is JED, convert to binary */ + if (is_jed) + { + /* read the JEDEC data */ + err = jed_parse(*src, &jed); + src.reset(); + switch (err) + { + case JEDERR_INVALID_DATA: fprintf(stderr, "Fatal error: Invalid .JED file\n"); result = 1; goto end; + case JEDERR_BAD_XMIT_SUM: fprintf(stderr, "Fatal error: Bad transmission checksum\n"); result = 1; goto end; + case JEDERR_BAD_FUSE_SUM: fprintf(stderr, "Fatal error: Bad fusemap checksum\n"); result = 1; goto end; + } + } + else + { + /* read the binary data */ + err = jedbin_parse(*src, &jed); + src.reset(); + switch (err) + { + case JEDERR_INVALID_DATA: fprintf(stderr, "Fatal error: Invalid binary JEDEC file\n"); result = 1; goto end; + } + } + + for (index = 0; index < std::size(paldata); ++index) + { + if (paldata[index].numfuses == jed.numfuses) + { + printf("%s\n", paldata[index].name); + } + } + +end: + return result; +} + + + /*------------------------------------------------- main - primary entry point -------------------------------------------------*/ @@ -7584,9 +8252,10 @@ static int command_viewlist(int argc, char *argv[]) int main(int argc, char *argv[]) { command_entry command_entries[] = { - {"-convert", &command_convert}, - {"-view", &command_view}, - {"-viewlist", &command_viewlist}}; + {"-convert", &command_convert}, + {"-view", &command_view}, + {"-viewlist", &command_viewlist}, + {"-listcompatible", &command_listcompatible}}; int index; if (argc < 2) @@ -7594,7 +8263,7 @@ int main(int argc, char *argv[]) return print_usage(); } - for (index = 0; index < ARRAY_LENGTH(command_entries); ++index) + for (index = 0; index < std::size(command_entries); ++index) { if (!strcmp(argv[1], command_entries[index].command)) return command_entries[index].command_func(argc - 2, &argv[2]); diff --git a/src/tools/ldresample.cpp b/src/tools/ldresample.cpp index 5386ac31229..4fcd19c3afc 100644 --- a/src/tools/ldresample.cpp +++ b/src/tools/ldresample.cpp @@ -8,17 +8,18 @@ ****************************************************************************/ -#include <stdio.h> -#include <ctype.h> -#include <stdlib.h> -#include <math.h> -#include <new> -#include <assert.h> +#include "avhuff.h" #include "bitmap.h" #include "chd.h" -#include "avhuff.h" #include "vbiparse.h" +#include <cassert> +#include <cctype> +#include <cmath> +#include <cstdio> +#include <cstdlib> +#include <new> + //************************************************************************** @@ -46,18 +47,18 @@ const uint32_t MINIMUM_SIGNAL_COUNT = 20; struct movie_info { - double framerate; - int iframerate; - int numfields; - int width; - int height; - int samplerate; - int channels; - int interlaced; - bitmap_yuy16 bitmap; - std::vector<int16_t> lsound; - std::vector<int16_t> rsound; - uint32_t samples; + double framerate; + int iframerate; + int numfields; + int width; + int height; + int samplerate; + int channels; + int interlaced; + bitmap_yuy16 bitmap; + std::vector<int16_t> lsound; + std::vector<int16_t> rsound; + uint32_t samples; }; @@ -156,22 +157,22 @@ inline uint32_t sample_number_to_field(const movie_info &info, uint32_t samplenu // information about it //------------------------------------------------- -static chd_error open_chd(chd_file &file, const char *filename, movie_info &info) +static std::error_condition open_chd(chd_file &file, const char *filename, movie_info &info) { // open the file - chd_error chderr = file.open(filename); - if (chderr != CHDERR_NONE) + std::error_condition chderr = file.open(filename); + if (chderr) { - fprintf(stderr, "Error opening CHD file: %s\n", chd_file::error_string(chderr)); + fprintf(stderr, "Error opening CHD file: %s\n", chderr.message().c_str()); return chderr; } // get the metadata std::string metadata; chderr = file.read_metadata(AV_METADATA_TAG, 0, metadata); - if (chderr != CHDERR_NONE) + if (chderr) { - fprintf(stderr, "Error getting A/V metadata: %s\n", chd_file::error_string(chderr)); + fprintf(stderr, "Error getting A/V metadata: %s\n", chderr.message().c_str()); return chderr; } @@ -180,7 +181,7 @@ static chd_error open_chd(chd_file &file, const char *filename, movie_info &info if (sscanf(metadata.c_str(), AV_METADATA_FORMAT, &fps, &fpsfrac, &width, &height, &interlaced, &channels, &rate) != 7) { fprintf(stderr, "Improperly formatted metadata\n"); - return CHDERR_INVALID_DATA; + return chd_file::error::INVALID_METADATA; } // extract movie info @@ -197,7 +198,7 @@ static chd_error open_chd(chd_file &file, const char *filename, movie_info &info info.bitmap.resize(info.width, info.height); info.lsound.resize(info.samplerate); info.rsound.resize(info.samplerate); - return CHDERR_NONE; + return std::error_condition(); } @@ -205,28 +206,28 @@ static chd_error open_chd(chd_file &file, const char *filename, movie_info &info // create_chd - create a new CHD file //------------------------------------------------- -static chd_error create_chd(chd_file_compressor &file, const char *filename, chd_file &source, const movie_info &info) +static std::error_condition create_chd(chd_file_compressor &file, const char *filename, chd_file &source, const movie_info &info) { // create the file chd_codec_type compression[4] = { CHD_CODEC_AVHUFF }; - chd_error chderr = file.create(filename, source.logical_bytes(), source.hunk_bytes(), source.unit_bytes(), compression); - if (chderr != CHDERR_NONE) + std::error_condition chderr = file.create(filename, source.logical_bytes(), source.hunk_bytes(), source.unit_bytes(), compression); + if (chderr) { - fprintf(stderr, "Error creating new CHD file: %s\n", chd_file::error_string(chderr)); + fprintf(stderr, "Error creating new CHD file: %s\n", chderr.message().c_str()); return chderr; } // clone the metadata chderr = file.clone_all_metadata(source); - if (chderr != CHDERR_NONE) + if (chderr) { - fprintf(stderr, "Error cloning metadata: %s\n", chd_file::error_string(chderr)); + fprintf(stderr, "Error cloning metadata: %s\n", chderr.message().c_str()); return chderr; } // begin compressing file.compress_begin(); - return CHDERR_NONE; + return std::error_condition(); } @@ -237,8 +238,8 @@ static chd_error create_chd(chd_file_compressor &file, const char *filename, chd static bool read_chd(chd_file &file, uint32_t field, movie_info &info, uint32_t soundoffs) { // configure the codec - avhuff_decompress_config avconfig; - avconfig.video.wrap(info.bitmap, info.bitmap.cliprect()); + avhuff_decoder::config avconfig; + avconfig.video = &info.bitmap; avconfig.maxsamples = info.lsound.size(); avconfig.actsamples = &info.samples; avconfig.audio[0] = &info.lsound[soundoffs]; @@ -248,8 +249,8 @@ 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 - chd_error chderr = file.read_hunk(field, nullptr); - return (chderr == CHDERR_NONE); + std::error_condition chderr = file.codec_process_hunk(field); + return !chderr; } @@ -507,6 +508,7 @@ int main(int argc, char *argv[]) // verify arguments if (argc < 2) return usage(); + const char *srcfilename = argv[1]; const char *dstfilename = (argc < 3) ? nullptr : argv[2]; double offset = (argc < 4) ? 0.0 : atof(argv[3]); @@ -524,8 +526,8 @@ int main(int argc, char *argv[]) // open the source file chd_file srcfile; movie_info info; - chd_error err = open_chd(srcfile, srcfilename, info); - if (err != CHDERR_NONE) + std::error_condition err = open_chd(srcfile, srcfilename, info); + if (err) { fprintf(stderr, "Unable to open file '%s'\n", srcfilename); return 1; @@ -537,9 +539,9 @@ int main(int argc, char *argv[]) printf("Sample rate: %dHz\n", info.samplerate); printf("Total fields: %d\n", info.numfields); - // if we don't have a destination file, scan for edges if (dstfilename == nullptr) { + // if we don't have a destination file, scan for edges for (uint32_t fieldnum = 60; fieldnum < info.numfields - 60; fieldnum += 30) { fprintf(stderr, "Field %5d\r", fieldnum); @@ -547,14 +549,14 @@ int main(int argc, char *argv[]) find_edge_near_field(srcfile, fieldnum, info, true, delta); } } - - // otherwise, resample the source to the destination else { + // otherwise, resample the source to the destination + // open the destination file - chd_resample_compressor dstfile(srcfile, info, int64_t(offset * 65536.0 * 256.0), int64_t(slope * 65536.0 * 256.0)); - err = create_chd(dstfile, dstfilename, srcfile, info); - if (!dstfile.opened()) + auto dstfile = std::make_unique<chd_resample_compressor>(srcfile, info, int64_t(offset * 65536.0 * 256.0), int64_t(slope * 65536.0 * 256.0)); + err = create_chd(*dstfile, dstfilename, srcfile, info); + if (!dstfile->opened()) { fprintf(stderr, "Unable to create file '%s'\n", dstfilename); return 1; @@ -563,7 +565,7 @@ int main(int argc, char *argv[]) // loop over all the fields in the source file double progress, ratio; osd_ticks_t last_update = 0; - while (dstfile.compress_continue(progress, ratio) == CHDERR_COMPRESSING) + while (dstfile->compress_continue(progress, ratio) == chd_file::error::COMPRESSING) if (osd_ticks() - last_update > osd_ticks_per_second() / 4) { last_update = osd_ticks(); diff --git a/src/tools/ldverify.cpp b/src/tools/ldverify.cpp index 2a326508323..bdb3b8c0a1f 100644 --- a/src/tools/ldverify.cpp +++ b/src/tools/ldverify.cpp @@ -8,18 +8,19 @@ ****************************************************************************/ -#include <stdio.h> -#include <stdlib.h> -#include <ctype.h> -#include <new> -#include <assert.h> -#include "coretmpl.h" -#include "aviio.h" #include "avhuff.h" +#include "aviio.h" #include "bitmap.h" #include "chd.h" +#include "coretmpl.h" #include "vbiparse.h" +#include <cassert> +#include <cctype> +#include <cstdio> +#include <cstdlib> +#include <new> + //************************************************************************** @@ -174,10 +175,10 @@ static void *open_chd(const char *filename, movie_info &info) auto chd = new chd_file; // open the file - chd_error chderr = chd->open(filename); - if (chderr != CHDERR_NONE) + std::error_condition chderr = chd->open(filename); + if (chderr) { - fprintf(stderr, "Error opening CHD file: %s\n", chd_file::error_string(chderr)); + fprintf(stderr, "Error opening CHD file: %s\n", chderr.message().c_str()); delete chd; return nullptr; } @@ -185,9 +186,9 @@ static void *open_chd(const char *filename, movie_info &info) // get the metadata std::string metadata; chderr = chd->read_metadata(AV_METADATA_TAG, 0, metadata); - if (chderr != CHDERR_NONE) + if (chderr) { - fprintf(stderr, "Error getting A/V metadata: %s\n", chd_file::error_string(chderr)); + fprintf(stderr, "Error getting A/V metadata: %s\n", chderr.message().c_str()); delete chd; return nullptr; } @@ -235,8 +236,10 @@ static int read_chd(void *file, int frame, bitmap_yuy16 &bitmap, int16_t *lsound for (int fieldnum = 0; fieldnum < interlace_factor; fieldnum++) { // make a fake bitmap for this field - avhuff_decompress_config avconfig; - avconfig.video.wrap(&bitmap.pix16(fieldnum), bitmap.width(), bitmap.height() / interlace_factor, bitmap.rowpixels() * interlace_factor); + bitmap_yuy16 video; + video.wrap(&bitmap.pix(fieldnum), bitmap.width(), bitmap.height() / interlace_factor, bitmap.rowpixels() * interlace_factor); + avhuff_decoder::config avconfig; + avconfig.video = &video; // configure the codec uint32_t numsamples; @@ -249,8 +252,8 @@ 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 - chd_error chderr = chdfile->read_hunk(frame * interlace_factor + fieldnum, nullptr); - if (chderr != CHDERR_NONE) + std::error_condition chderr = chdfile->codec_process_hunk(frame * interlace_factor + fieldnum); + if (chderr) return false; // account for samples read @@ -320,7 +323,7 @@ static void verify_video(video_info &video, int frame, bitmap_yuy16 &bitmap) // parse the VBI data vbi_metadata metadata; - vbi_parse_all(&bitmap.pix16(fieldnum), bitmap.rowpixels() * 2, bitmap.width(), 8, &metadata); + vbi_parse_all(&bitmap.pix(fieldnum), bitmap.rowpixels() * 2, bitmap.width(), 8, &metadata); // if we have data in both 17 and 18, it should match if (metadata.line17 != 0 && metadata.line18 != 0 && metadata.line17 != metadata.line18) @@ -484,11 +487,11 @@ static void verify_video(video_info &video, int frame, bitmap_yuy16 &bitmap) { for (int x = 16; x < 720 - 16; x++) { - yhisto[bitmap.pix16(y, x) >> 8]++; + yhisto[bitmap.pix(y, x) >> 8]++; if (x % 2 == 0) - cbhisto[bitmap.pix16(y, x) & 0xff]++; + cbhisto[bitmap.pix(y, x) & 0xff]++; else - crhisto[bitmap.pix16(y, x) & 0xff]++; + crhisto[bitmap.pix(y, x) & 0xff]++; } pixels += 720 - 16 - 16; } diff --git a/src/tools/pngcmp.cpp b/src/tools/pngcmp.cpp index af104e928b3..480f9fadb14 100644 --- a/src/tools/pngcmp.cpp +++ b/src/tools/pngcmp.cpp @@ -8,16 +8,19 @@ ****************************************************************************/ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <assert.h> -#include "osdcore.h" +#include "corefile.h" #include "png.h" +#include "osdfile.h" + +#include <cassert> +#include <cctype> +#include <cstdio> +#include <cstdlib> +#include <cstring> #include <new> + /*************************************************************************** CONSTANTS & DEFINES ***************************************************************************/ @@ -73,56 +76,55 @@ static int generate_png_diff(const std::string& imgfile1, const std::string& img bitmap_argb32 finalbitmap; int width, height, maxwidth; util::core_file::ptr file; - osd_file::error filerr; - png_error pngerr; + std::error_condition filerr; int error = 100; - bool bitmaps_differ; - int x, y; /* open the source image */ filerr = util::core_file::open(imgfile1, OPEN_FLAG_READ, file); - if (filerr != osd_file::error::NONE) + if (filerr) { - printf("Could not open %s (%d)\n", imgfile1.c_str(), int(filerr)); + printf("Could not open %s (%s)\n", imgfile1.c_str(), filerr.message().c_str()); goto error; } /* load the source image */ - pngerr = png_read_bitmap(*file, bitmap1); + filerr = util::png_read_bitmap(*file, bitmap1); file.reset(); - if (pngerr != PNGERR_NONE) + if (filerr) { - printf("Could not read %s (%d)\n", imgfile1.c_str(), pngerr); + printf("Could not read %s (%s)\n", imgfile1.c_str(), filerr.message().c_str()); goto error; } /* open the source image */ filerr = util::core_file::open(imgfile2, OPEN_FLAG_READ, file); - if (filerr != osd_file::error::NONE) + if (filerr) { - printf("Could not open %s (%d)\n", imgfile2.c_str(), int(filerr)); + printf("Could not open %s (%s)\n", imgfile2.c_str(), filerr.message().c_str()); goto error; } /* load the source image */ - pngerr = png_read_bitmap(*file, bitmap2); + filerr = util::png_read_bitmap(*file, bitmap2); file.reset(); - if (pngerr != PNGERR_NONE) + if (filerr) { - printf("Could not read %s (%d)\n", imgfile2.c_str(), pngerr); + printf("Could not read %s (%s)\n", imgfile2.c_str(), filerr.message().c_str()); goto error; } /* if the sizes are different, we differ; otherwise start off assuming we are the same */ + bool bitmaps_differ; bitmaps_differ = (bitmap2.width() != bitmap1.width() || bitmap2.height() != bitmap1.height()); /* compare scanline by scanline */ - for (y = 0; y < bitmap2.height() && !bitmaps_differ; y++) + for (int y = 0; y < bitmap2.height() && !bitmaps_differ; y++) { - uint32_t *base = &bitmap1.pix32(y); - uint32_t *curr = &bitmap2.pix32(y); + uint32_t const *base = &bitmap1.pix(y); + uint32_t const *curr = &bitmap2.pix(y); /* scan the scanline */ + int x; for (x = 0; x < bitmap2.width(); x++) if (*base++ != *curr++) break; @@ -148,16 +150,16 @@ static int generate_png_diff(const std::string& imgfile1, const std::string& img /* now copy and compare each set of bitmaps */ int curheight = std::max(bitmap1.height(), bitmap2.height()); /* iterate over rows in these bitmaps */ - for (y = 0; y < curheight; y++) + for (int y = 0; y < curheight; y++) { - uint32_t *src1 = (y < bitmap1.height()) ? &bitmap1.pix32(y) : nullptr; - uint32_t *src2 = (y < bitmap2.height()) ? &bitmap2.pix32(y) : nullptr; - uint32_t *dst1 = &finalbitmap.pix32(y); - uint32_t *dst2 = &finalbitmap.pix32(y, bitmap1.width() + BITMAP_SPACE); - uint32_t *dstdiff = &finalbitmap.pix32(y, bitmap1.width() + BITMAP_SPACE + maxwidth + BITMAP_SPACE); + uint32_t const *src1 = (y < bitmap1.height()) ? &bitmap1.pix(y) : nullptr; + uint32_t const *src2 = (y < bitmap2.height()) ? &bitmap2.pix(y) : nullptr; + uint32_t *dst1 = &finalbitmap.pix(y); + uint32_t *dst2 = &finalbitmap.pix(y, bitmap1.width() + BITMAP_SPACE); + uint32_t *dstdiff = &finalbitmap.pix(y, bitmap1.width() + BITMAP_SPACE + maxwidth + BITMAP_SPACE); /* now iterate over columns */ - for (x = 0; x < maxwidth; x++) + for (int x = 0; x < maxwidth; x++) { int pix1 = -1, pix2 = -2; @@ -171,16 +173,16 @@ static int generate_png_diff(const std::string& imgfile1, const std::string& img /* write the final PNG */ filerr = util::core_file::open(outfilename, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, file); - if (filerr != osd_file::error::NONE) + if (filerr) { - printf("Could not open %s (%d)\n", outfilename.c_str(), int(filerr)); + printf("Could not open %s (%s)\n", outfilename.c_str(), filerr.message().c_str()); goto error; } - pngerr = png_write_bitmap(*file, nullptr, finalbitmap, 0, nullptr); + filerr = util::png_write_bitmap(*file, nullptr, finalbitmap, 0, nullptr); file.reset(); - if (pngerr != PNGERR_NONE) + if (filerr) { - printf("Could not write %s (%d)\n", outfilename.c_str(), pngerr); + printf("Could not write %s (%s)\n", outfilename.c_str(), filerr.message().c_str()); goto error; } } diff --git a/src/tools/regrep.cpp b/src/tools/regrep.cpp index 91dcaecd518..316ef805f5a 100644 --- a/src/tools/regrep.cpp +++ b/src/tools/regrep.cpp @@ -6,14 +6,21 @@ ****************************************************************************/ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <new> -#include <assert.h> -#include "osdcore.h" +#include "corefile.h" +#include "corestr.h" +#include "path.h" #include "png.h" +#include "strformat.h" + +#include "osdcomm.h" + +#include <algorithm> +#include <cassert> +#include <cctype> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <new> /*************************************************************************** @@ -61,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]; }; @@ -148,15 +155,15 @@ static int CLIB_DECL compare_file(const void *file0ptr, const void *file1ptr); static summary_file *sort_file_list(void); /* HTML helpers */ -static util::core_file::ptr create_file_and_output_header(std::string &filename, std::string &templatefile, std::string &title); -static void output_footer_and_close_file(util::core_file::ptr &&file, std::string &templatefile, std::string &title); +static util::core_file::ptr create_file_and_output_header(std::string_view filename, std::string_view templatefile, const std::string &title); +static void output_footer_and_close_file(util::write_stream::ptr &&file, std::string_view templatefile, const std::string &title); /* report generators */ -static void output_report(std::string &dirname, std::string &tempheader, std::string &tempfooter, summary_file *filelist); +static void output_report(std::string_view dirname, std::string_view tempheader, std::string_view tempfooter, summary_file *filelist); static int compare_screenshots(summary_file *curfile); -static int generate_png_diff(const summary_file *curfile, std::string &destdir, const char *destname); -static void create_linked_file(std::string &dirname, const summary_file *curfile, const summary_file *prevfile, const summary_file *nextfile, const char *pngfile, std::string &tempheader, std::string &tempfooter); -static void append_driver_list_table(const char *header, std::string &dirname, util::core_file &indexfile, const summary_file *listhead, std::string &tempheader, std::string &tempfooter); +static int generate_png_diff(const summary_file *curfile, std::string_view destdir, std::string_view destname); +static void create_linked_file(std::string_view dirname, const summary_file *curfile, const summary_file *prevfile, const summary_file *nextfile, std::string_view pngfile, std::string_view tempheader, std::string_view tempfooter); +static void append_driver_list_table(const char *header, std::string_view dirname, util::core_file &indexfile, const summary_file *listhead, std::string_view tempheader, std::string_view tempfooter); @@ -218,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; @@ -235,7 +242,7 @@ int main(int argc, char *argv[]) /* read the template file into an astring */ std::string tempheader; - if (util::core_file::load(tempfilename.c_str(), &buffer, bufsize) == osd_file::error::NONE) + if (!util::core_file::load(tempfilename, &buffer, bufsize)) { tempheader.assign((const char *)buffer, bufsize); free(buffer); @@ -284,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) @@ -292,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); @@ -504,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; @@ -560,18 +571,18 @@ static summary_file *sort_file_list(void) HTML file with a standard header -------------------------------------------------*/ -static util::core_file::ptr create_file_and_output_header(std::string &filename, std::string &templatefile, std::string &title) +static util::core_file::ptr create_file_and_output_header(std::string_view filename, std::string_view templatefile, const std::string &title) { util::core_file::ptr file; /* create the indexfile */ - if (util::core_file::open(filename, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS | OPEN_FLAG_NO_BOM, file) != osd_file::error::NONE) + if (util::core_file::open(filename, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS | OPEN_FLAG_NO_BOM, file)) return util::core_file::ptr(); /* print a header */ std::string modified(templatefile); - strreplace(modified, "<!--TITLE-->", title.c_str()); - file->write(modified.c_str(), modified.length()); + strreplace(modified, "<!--TITLE-->", title); + /*auto const [err, written] =*/ write(*file, modified.c_str(), modified.length()); // FIXME: check for errors /* return the file */ return file; @@ -583,11 +594,11 @@ static util::core_file::ptr create_file_and_output_header(std::string &filename, standard footer to an HTML file and close it -------------------------------------------------*/ -static void output_footer_and_close_file(util::core_file::ptr &&file, std::string &templatefile, std::string &title) +static void output_footer_and_close_file(util::write_stream::ptr &&file, std::string_view templatefile, const std::string &title) { std::string modified(templatefile); - strreplace(modified, "<!--TITLE-->", title.c_str()); - file->write(modified.c_str(), modified.length()); + strreplace(modified, "<!--TITLE-->", title); + /*auto const [err, written] =*/ write(*file, modified.c_str(), modified.length()); // FIXME: check for errors file.reset(); } @@ -602,12 +613,11 @@ static void output_footer_and_close_file(util::core_file::ptr &&file, std::strin report HTML files -------------------------------------------------*/ -static void output_report(std::string &dirname, std::string &tempheader, std::string &tempfooter, summary_file *filelist) +static void output_report(std::string_view dirname, std::string_view tempheader, std::string_view tempfooter, summary_file *filelist) { summary_file *buckethead[BUCKET_COUNT], **buckettailptr[BUCKET_COUNT]; summary_file *curfile; std::string title("MAME Regressions"); - std::string tempname; int listnum, bucknum; util::core_file::ptr indexfile; int count = 0, total; @@ -686,7 +696,7 @@ static void output_report(std::string &dirname, std::string &tempheader, std::st *buckettailptr[bucknum] = nullptr; /* output header */ - tempname = string_format("%s" PATH_SEPARATOR "%s", dirname.c_str(), "index.html"); + std::string tempname = util::path_concat(dirname, "index.html"); indexfile = create_file_and_output_header(tempname, tempheader, title); if (!indexfile) { @@ -695,7 +705,7 @@ static void output_report(std::string &dirname, std::string &tempheader, std::st } /* iterate over buckets and output them */ - for (bucknum = 0; bucknum < ARRAY_LENGTH(bucket_output_order); bucknum++) + for (bucknum = 0; bucknum < std::size(bucket_output_order); bucknum++) { int curbucket = bucket_output_order[bucknum]; @@ -719,43 +729,43 @@ static void output_report(std::string &dirname, std::string &tempheader, std::st static int compare_screenshots(summary_file *curfile) { bitmap_argb32 bitmaps[MAX_COMPARES]; - int unique[MAX_COMPARES]; + int unique[MAX_COMPARES]{}; int numunique = 0; - int listnum; /* iterate over all files and load their bitmaps */ - for (listnum = 0; listnum < list_count; listnum++) + for (int listnum = 0; listnum < list_count; listnum++) if (curfile->status[listnum] == STATUS_SUCCESS) { std::string fullname; - osd_file::error filerr; + std::error_condition filerr; util::core_file::ptr file; /* get the filename for the image */ - fullname = string_format("%s" PATH_SEPARATOR "snap" PATH_SEPARATOR "%s" PATH_SEPARATOR "final.png", lists[listnum].dir, curfile->name); + fullname = util::path_concat(lists[listnum].dir, "snap", curfile->name, "final.png"); /* open the file */ filerr = util::core_file::open(fullname, OPEN_FLAG_READ, file); /* if that failed, look in the old location */ - if (filerr != osd_file::error::NONE) + if (filerr) { /* get the filename for the image */ - fullname = string_format("%s" PATH_SEPARATOR "snap" PATH_SEPARATOR "_%s.png", lists[listnum].dir, curfile->name); + fullname = util::path_concat(lists[listnum].dir, "snap", util::string_format("_%s.png", curfile->name)); /* open the file */ filerr = util::core_file::open(fullname, OPEN_FLAG_READ, file); } /* if that worked, load the file */ - if (filerr == osd_file::error::NONE) + if (!filerr) { - png_read_bitmap(*file, bitmaps[listnum]); + util::png_read_bitmap(*file, bitmaps[listnum]); file.reset(); } } /* now find all the different bitmap types */ + int listnum; for (listnum = 0; listnum < list_count; listnum++) { curfile->matchbitmap[listnum] = 0xff; @@ -774,8 +784,8 @@ static int compare_screenshots(summary_file *curfile) /* compare scanline by scanline */ for (int y = 0; y < this_bitmap.height() && !bitmaps_differ; y++) { - uint32_t *base = &base_bitmap.pix32(y); - uint32_t *curr = &this_bitmap.pix32(y); + uint32_t const *base = &base_bitmap.pix(y); + uint32_t const *curr = &this_bitmap.pix(y); /* scan the scanline */ int x; @@ -826,41 +836,38 @@ static int compare_screenshots(summary_file *curfile) side with a third set of differences -------------------------------------------------*/ -static int generate_png_diff(const summary_file *curfile, std::string &destdir, const char *destname) +static int generate_png_diff(const summary_file *curfile, std::string_view destdir, std::string_view destname) { bitmap_argb32 bitmaps[MAX_COMPARES]; std::string srcimgname; std::string dstfilename; - std::string tempname; bitmap_argb32 finalbitmap; int width, height, maxwidth; int bitmapcount = 0; - int listnum, bmnum; util::core_file::ptr file; - osd_file::error filerr; - png_error pngerr; + std::error_condition filerr; int error = -1; int starty; /* generate the common source filename */ - dstfilename = string_format("%s" PATH_SEPARATOR "%s", destdir.c_str(), destname); - srcimgname = string_format("snap" PATH_SEPARATOR "%s" PATH_SEPARATOR "final.png", curfile->name); + dstfilename = util::path_concat(destdir, destname); + srcimgname = util::path_concat("snap", curfile->name, "final.png"); /* open and load all unique bitmaps */ - for (listnum = 0; listnum < list_count; listnum++) + for (int listnum = 0; listnum < list_count; listnum++) if (curfile->matchbitmap[listnum] == listnum) { - tempname = string_format("%s" PATH_SEPARATOR "%s", lists[listnum].dir, srcimgname.c_str()); + std::string tempname = util::path_concat(lists[listnum].dir, srcimgname); /* open the source image */ filerr = util::core_file::open(tempname, OPEN_FLAG_READ, file); - if (filerr != osd_file::error::NONE) + if (filerr) goto error; /* load the source image */ - pngerr = png_read_bitmap(*file, bitmaps[bitmapcount++]); + filerr = util::png_read_bitmap(*file, bitmaps[bitmapcount++]); file.reset(); - if (pngerr != PNGERR_NONE) + if (filerr) goto error; } @@ -871,7 +878,7 @@ static int generate_png_diff(const summary_file *curfile, std::string &destdir, /* determine the size of the final bitmap */ height = width = 0; maxwidth = bitmaps[0].width(); - for (bmnum = 1; bmnum < bitmapcount; bmnum++) + for (int bmnum = 1; bmnum < bitmapcount; bmnum++) { int curwidth; @@ -891,24 +898,23 @@ static int generate_png_diff(const summary_file *curfile, std::string &destdir, /* now copy and compare each set of bitmaps */ starty = 0; - for (bmnum = 1; bmnum < bitmapcount; bmnum++) + for (int bmnum = 1; bmnum < bitmapcount; bmnum++) { - bitmap_argb32 &bitmap1 = bitmaps[0]; - bitmap_argb32 &bitmap2 = bitmaps[bmnum]; + bitmap_argb32 const &bitmap1 = bitmaps[0]; + bitmap_argb32 const &bitmap2 = bitmaps[bmnum]; int curheight = std::max(bitmap1.height(), bitmap2.height()); - int x, y; /* iterate over rows in these bitmaps */ - for (y = 0; y < curheight; y++) + for (int y = 0; y < curheight; y++) { - uint32_t *src1 = (y < bitmap1.height()) ? &bitmap1.pix32(y) : nullptr; - uint32_t *src2 = (y < bitmap2.height()) ? &bitmap2.pix32(y) : nullptr; - uint32_t *dst1 = &finalbitmap.pix32(starty + y, 0); - uint32_t *dst2 = &finalbitmap.pix32(starty + y, bitmap1.width() + BITMAP_SPACE); - uint32_t *dstdiff = &finalbitmap.pix32(starty + y, bitmap1.width() + BITMAP_SPACE + maxwidth + BITMAP_SPACE); + uint32_t const *src1 = (y < bitmap1.height()) ? &bitmap1.pix(y) : nullptr; + uint32_t const *src2 = (y < bitmap2.height()) ? &bitmap2.pix(y) : nullptr; + uint32_t *dst1 = &finalbitmap.pix(starty + y, 0); + uint32_t *dst2 = &finalbitmap.pix(starty + y, bitmap1.width() + BITMAP_SPACE); + uint32_t *dstdiff = &finalbitmap.pix(starty + y, bitmap1.width() + BITMAP_SPACE + maxwidth + BITMAP_SPACE); /* now iterate over columns */ - for (x = 0; x < maxwidth; x++) + for (int x = 0; x < maxwidth; x++) { int pix1 = -1, pix2 = -2; @@ -926,11 +932,11 @@ static int generate_png_diff(const summary_file *curfile, std::string &destdir, /* write the final PNG */ filerr = util::core_file::open(dstfilename, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, file); - if (filerr != osd_file::error::NONE) + if (filerr) goto error; - pngerr = png_write_bitmap(*file, nullptr, finalbitmap, 0, nullptr); + filerr = util::png_write_bitmap(*file, nullptr, finalbitmap, 0, nullptr); file.reset(); - if (pngerr != PNGERR_NONE) + if (filerr) goto error; /* if we get here, we are error free */ @@ -948,7 +954,7 @@ error: file between differing versions -------------------------------------------------*/ -static void create_linked_file(std::string &dirname, const summary_file *curfile, const summary_file *prevfile, const summary_file *nextfile, const char *pngfile, std::string &tempheader, std::string &tempfooter) +static void create_linked_file(std::string_view dirname, const summary_file *curfile, const summary_file *prevfile, const summary_file *nextfile, std::string_view pngfile, std::string_view tempheader, std::string_view tempfooter) { std::string linkname; std::string filename; @@ -957,11 +963,11 @@ static void create_linked_file(std::string &dirname, const summary_file *curfile int listnum; /* create the filename */ - filename = string_format("%s.html", curfile->name); + filename = util::string_format("%s.html", curfile->name); /* output header */ - title = string_format("%s Regressions (%s)", curfile->name, curfile->source); - linkname = string_format("%s" PATH_SEPARATOR "%s", dirname.c_str(), filename.c_str()); + title = util::string_format("%s Regressions (%s)", curfile->name, curfile->source); + linkname = util::path_concat(dirname, filename); linkfile = create_file_and_output_header(linkname, tempheader, title); if (linkfile == nullptr) { @@ -993,7 +999,7 @@ static void create_linked_file(std::string &dirname, const summary_file *curfile linkfile->printf("\n\t<h2>%s</h2>\n", lists[listnum].version); linkfile->printf("\t<p>\n"); linkfile->printf("\t<b>Status:</b> %s\n", status_text[curfile->status[listnum]]); - if (pngfile != nullptr) + if (!pngfile.empty()) imageindex = get_unique_index(curfile, listnum); if (imageindex != -1) linkfile->printf(" [%d]", imageindex); @@ -1002,13 +1008,13 @@ static void create_linked_file(std::string &dirname, const summary_file *curfile { linkfile->printf("\t<p>\n"); linkfile->printf("\t<b>Errors:</b>\n"); - linkfile->printf("\t<pre>%s</pre>\n", curfile->text[listnum].c_str()); + linkfile->printf("\t<pre>%s</pre>\n", curfile->text[listnum]); linkfile->printf("\t</p>\n"); } } /* output link to the image */ - if (pngfile != nullptr) + if (!pngfile.empty()) { linkfile->printf("\n\t<h2>Screenshot Comparisons</h2>\n"); linkfile->printf("\t<p>\n"); @@ -1026,7 +1032,7 @@ static void create_linked_file(std::string &dirname, const summary_file *curfile of drivers from a list to an HTML file -------------------------------------------------*/ -static void append_driver_list_table(const char *header, std::string &dirname, util::core_file &indexfile, const summary_file *listhead, std::string &tempheader, std::string &tempfooter) +static void append_driver_list_table(const char *header, std::string_view dirname, util::core_file &indexfile, const summary_file *listhead, std::string_view tempheader, std::string_view tempfooter) { const summary_file *curfile, *prevfile; int width = 100 / (2 + list_count); @@ -1054,7 +1060,6 @@ static void append_driver_list_table(const char *header, std::string &dirname, u for (prevfile = nullptr, curfile = listhead; curfile != nullptr; prevfile = curfile, curfile = curfile->next) { int rowspan = 0, uniqueshots = 0; - char pngdiffname[40]; /* if this is the first entry in this source file, count how many rows we need to span */ if (prevfile == nullptr || strcmp(prevfile->source, curfile->source) != 0) @@ -1068,19 +1073,19 @@ static void append_driver_list_table(const char *header, std::string &dirname, u } /* create screenshots if necessary */ - pngdiffname[0] = 0; + std::string pngdiffname; for (listnum = 0; listnum < list_count; listnum++) if (curfile->matchbitmap[listnum] == listnum) uniqueshots++; if (uniqueshots > 1) { - sprintf(pngdiffname, "compare_%s.png", curfile->name); + pngdiffname = util::string_format("compare_%s.png", curfile->name); if (generate_png_diff(curfile, dirname, pngdiffname) != 0) - pngdiffname[0] = 0; + pngdiffname.clear(); } /* create a linked file */ - create_linked_file(dirname, curfile, prevfile, curfile->next, (pngdiffname[0] == 0) ? nullptr : pngdiffname, tempheader, tempfooter); + create_linked_file(dirname, curfile, prevfile, curfile->next, pngdiffname, tempheader, tempfooter); /* create a row */ indexfile.printf("\t\t<tr>\n\t\t\t"); @@ -1091,7 +1096,7 @@ static void append_driver_list_table(const char *header, std::string &dirname, u { int unique_index = -1; - if (pngdiffname[0] != 0) + if (!pngdiffname.empty()) unique_index = get_unique_index(curfile, listnum); if (unique_index != -1) indexfile.printf("<td><span style=\"%s\"> </span> %s [<a href=\"%s\" target=\"blank\">%d</a>]</td>", status_color[curfile->status[listnum]], status_text[curfile->status[listnum]], pngdiffname, unique_index); diff --git a/src/tools/romcmp.cpp b/src/tools/romcmp.cpp index 6a781bc8c29..e3ae03c8f5e 100644 --- a/src/tools/romcmp.cpp +++ b/src/tools/romcmp.cpp @@ -8,25 +8,20 @@ ***************************************************************************/ +#include "hash.h" +#include "path.h" #include "unzip.h" -#include "osdcore.h" + +#include "osdfile.h" #include "osdcomm.h" -#include "hash.h" -#include <stdarg.h> -#include <stdlib.h> +#include <cstdarg> +#include <cstdlib> +#include <memory> #define MAX_FILES 1000 -#ifndef MAX_FILENAME_LEN -#define MAX_FILENAME_LEN 255 -#endif - -#ifndef PATH_DELIM -#define PATH_DELIM '/' -#endif - /* compare modes when one file is twice as long as the other */ @@ -105,369 +100,381 @@ static void compatiblemodes(int mode,int *start,int *end) struct fileinfo { - char name[MAX_FILENAME_LEN+1]; + std::string name; int size; - unsigned char *buf; /* file is read in here */ + std::unique_ptr<unsigned char []> buf; // file is read in here int listed; -}; -static fileinfo files[2][MAX_FILES]; -static float matchscore[MAX_FILES][MAX_FILES][TOTAL_MODES][TOTAL_MODES]; + static constexpr bool is_ascii_char(int ch) + { + return (ch >= 0x20 && ch < 0x7f) || (ch == '\n') || (ch == '\r') || (ch == '\t'); + } -static bool is_ascii_char(int ch) -{ - return (ch >= 0x20 && ch < 0x7f) || (ch == '\n') || (ch == '\r') || (ch == '\t'); -} -static void checkintegrity(const fileinfo *file, int side) -{ - if (file->buf == nullptr) return; + void checkintegrity(int side, bool all_hashes) const + { + if (!buf) + return; - /* check for bad data lines */ - unsigned mask0 = 0x0000; - unsigned mask1 = 0xffff; + if (all_hashes) + { + util::crc32_creator crc32; + util::sha1_creator sha1; + util::sum16_creator sum16; + crc32.append(buf.get(), size); + sha1.append(buf.get(), size); + sum16.append(buf.get(), size); + printf("%-23s %-23s [0x%x] CRC(%s) SHA1(%s) SUM(%s)\n", + (side & 1) ? name.c_str() : "", + (side & 2) ? name.c_str() : "", + size, + crc32.finish().as_string().c_str(), + sha1.finish().as_string().c_str(), + sum16.finish().as_string().c_str()); + side = 0; + } - bool is_ascii = true; - for (unsigned i = 0; i < file->size; i += 2) - { - is_ascii = is_ascii && is_ascii_char(file->buf[i]); - mask0 |= file->buf[i] << 8; - mask1 &= (file->buf[i] << 8) | 0x00ff; - if (i < file->size - 1) + // check for bad data lines + unsigned mask0 = 0x0000; + unsigned mask1 = 0xffff; + + bool is_ascii = true; + for (unsigned i = 0; i < size; i += 2) { - is_ascii = is_ascii && is_ascii_char(file->buf[i+1]); - mask0 |= file->buf[i+1]; - mask1 &= file->buf[i+1] | 0xff00; + is_ascii = is_ascii && is_ascii_char(buf[i]); + mask0 |= buf[i] << 8; + mask1 &= (buf[i] << 8) | 0x00ff; + if (i < size - 1) + { + is_ascii = is_ascii && is_ascii_char(buf[i+1]); + mask0 |= buf[i+1]; + mask1 &= buf[i+1] | 0xff00; + } + if (mask0 == 0xffff && mask1 == 0x0000) break; } - if (mask0 == 0xffff && mask1 == 0x0000) break; - } - if (is_ascii && mask0 == 0x7f7f && mask1 == 0) - { - printf("%-23s %-23s ASCII TEXT FILE\n", side ? "" : file->name, side ? file->name : ""); - return; - } + if (is_ascii && mask0 == 0x7f7f && mask1 == 0) + { + printf("%-23s %-23s ASCII TEXT FILE\n", (side & 1) ? name.c_str() : "", (side & 2) ? name.c_str() : ""); + return; + } - if (mask0 != 0xffff || mask1 != 0x0000) - { - int fixedmask; - int bits; + if (mask0 != 0xffff || mask1 != 0x0000) + { + int fixedmask; + int bits; - fixedmask = (~mask0 | mask1) & 0xffff; + fixedmask = (~mask0 | mask1) & 0xffff; - if (((mask0 >> 8) & 0xff) == (mask0 & 0xff) && ((mask1 >> 8) & 0xff) == (mask1 & 0xff)) - bits = 8; - else bits = 16; + if (((mask0 >> 8) & 0xff) == (mask0 & 0xff) && ((mask1 >> 8) & 0xff) == (mask1 & 0xff)) + bits = 8; + else bits = 16; - printf("%-23s %-23s FIXED BITS (",side ? "" : file->name,side ? file->name : ""); - for (int i = 0; i < bits; i++) - { - if (~mask0 & 0x8000) printf("0"); - else if (mask1 & 0x8000) printf("1"); - else printf("x"); + printf("%-23s %-23s FIXED BITS (", (side & 1) ? name.c_str() : "", (side & 2) ? name.c_str() : ""); + for (int i = 0; i < bits; i++) + { + if (~mask0 & 0x8000) printf("0"); + else if (mask1 & 0x8000) printf("1"); + else printf("x"); - mask0 <<= 1; - mask1 <<= 1; - } - printf(")\n"); + mask0 <<= 1; + mask1 <<= 1; + } + printf(")\n"); - /* if the file contains a fixed value, we don't need to do the other */ - /* validity checks */ - if (fixedmask == 0xffff || fixedmask == 0x00ff || fixedmask == 0xff00) - return; - } + /* if the file contains a fixed value, we don't need to do the other */ + /* validity checks */ + if (fixedmask == 0xffff || fixedmask == 0x00ff || fixedmask == 0xff00) + return; + } - unsigned addrbit = 1; - unsigned addrmirror = 0; - while (addrbit <= file->size/2) - { - unsigned i = 0; - for (i = 0; i < file->size; i++) + unsigned addrbit = 1; + unsigned addrmirror = 0; + while (addrbit <= size/2) { - if ((i ^ addrbit) < file->size && file->buf[i] != file->buf[i ^ addrbit]) break; + unsigned i = 0; + for (i = 0; i < size; i++) + { + if ((i ^ addrbit) < size && buf[i] != buf[i ^ addrbit]) break; + } + + if (i == size) + addrmirror |= addrbit; + + addrbit <<= 1; } - if (i == file->size) - addrmirror |= addrbit; + if (addrmirror != 0) + { + if (addrmirror == size/2) + { + printf("%-23s %-23s 1ST AND 2ND HALF IDENTICAL\n", (side & 1) ? name.c_str() : "", (side & 2) ? name.c_str() : ""); + util::hash_collection hash; + hash.compute(buf.get(), size / 2); + printf("%-23s %-23s %s\n", (side & 1) ? name.c_str() : "", (side & 2) ? name.c_str() : "", hash.attribute_string().c_str()); + } + else + { + printf("%-23s %-23s BADADDR", (side & 1) ? name.c_str() : "", (side & 2) ? name.c_str() : ""); + for (int i = 0; i < 24; i++) + { + if (size <= (1<<(23-i))) printf(" "); + else if (addrmirror & 0x800000) printf("-"); + else printf("x"); + addrmirror <<= 1; + } + printf("\n"); + } + return; + } - addrbit <<= 1; - } + unsigned sizemask = 1; + while (sizemask < size - 1) + sizemask = (sizemask << 1) | 1; - if (addrmirror != 0) - { - if (addrmirror == file->size/2) + mask0 = 0x000000; + mask1 = sizemask; + for (unsigned i = 0; i < size; i++) { - printf("%-23s %-23s 1ST AND 2ND HALF IDENTICAL\n", side ? "" : file->name, side ? file->name : ""); - util::hash_collection hash; - hash.begin(); - hash.buffer(file->buf, file->size / 2); - hash.end(); - printf("%-23s %-23s %s\n", side ? "" : file->name, side ? file->name : "", hash.attribute_string().c_str()); + if (buf[i] != 0xff) + { + mask0 |= i; + mask1 &= i; + if (mask0 == sizemask && mask1 == 0x00) break; + } } - else + + if (mask0 != sizemask || mask1 != 0x00) { - printf("%-23s %-23s BADADDR",side ? "" : file->name,side ? file->name : ""); + printf("%-23s %-23s ", (side & 1) ? name.c_str() : "", (side & 2) ? name.c_str() : ""); for (int i = 0; i < 24; i++) { - if (file->size <= (1<<(23-i))) printf(" "); - else if (addrmirror & 0x800000) printf("-"); + if (size <= (1<<(23-i))) printf(" "); + else if (~mask0 & 0x800000) printf("1"); + else if (mask1 & 0x800000) printf("0"); else printf("x"); - addrmirror <<= 1; + mask0 <<= 1; + mask1 <<= 1; } - printf("\n"); + printf(" = 0xFF\n"); + + return; } - return; - } - unsigned sizemask = 1; - while (sizemask < file->size - 1) - sizemask = (sizemask << 1) | 1; - mask0 = 0x000000; - mask1 = sizemask; - for (unsigned i = 0; i < file->size; i++) - { - if (file->buf[i] != 0xff) + mask0 = 0x000000; + mask1 = sizemask; + for (unsigned i = 0; i < size; i++) { - mask0 |= i; - mask1 &= i; - if (mask0 == sizemask && mask1 == 0x00) break; + if (buf[i] != 0x00) + { + mask0 |= i; + mask1 &= i; + if (mask0 == sizemask && mask1 == 0x00) break; + } } - } - if (mask0 != sizemask || mask1 != 0x00) - { - printf("%-23s %-23s ",side ? "" : file->name,side ? file->name : ""); - for (int i = 0; i < 24; i++) + if (mask0 != sizemask || mask1 != 0x00) { - if (file->size <= (1<<(23-i))) printf(" "); - else if (~mask0 & 0x800000) printf("1"); - else if (mask1 & 0x800000) printf("0"); - else printf("x"); - mask0 <<= 1; - mask1 <<= 1; - } - printf(" = 0xFF\n"); - - return; - } + printf("%-23s %-23s ", (side & 1) ? name.c_str() : "", (side & 2) ? name.c_str() : ""); + for (int i = 0; i < 24; i++) + { + if (size <= (1<<(23-i))) printf(" "); + else if ((mask0 & 0x800000) == 0) printf("1"); + else if (mask1 & 0x800000) printf("0"); + else printf("x"); + mask0 <<= 1; + mask1 <<= 1; + } + printf(" = 0x00\n"); + return; + } - mask0 = 0x000000; - mask1 = sizemask; - for (unsigned i = 0; i < file->size; i++) - { - if (file->buf[i] != 0x00) + mask0 = 0xff; + for (unsigned i = 0; i < size/4 && mask0 != 0x00; i++) { - mask0 |= i; - mask1 &= i; - if (mask0 == sizemask && mask1 == 0x00) break; + if (buf[ 2*i ] != 0x00) mask0 &= ~0x01; + if (buf[ 2*i ] != 0xff) mask0 &= ~0x02; + if (buf[ 2*i+1] != 0x00) mask0 &= ~0x04; + if (buf[ 2*i+1] != 0xff) mask0 &= ~0x08; + if (buf[size/2 + 2*i ] != 0x00) mask0 &= ~0x10; + if (buf[size/2 + 2*i ] != 0xff) mask0 &= ~0x20; + if (buf[size/2 + 2*i+1] != 0x00) mask0 &= ~0x40; + if (buf[size/2 + 2*i+1] != 0xff) mask0 &= ~0x80; } + + if (mask0 & 0x01) printf("%-23s %-23s 1ST HALF = 00xx\n", (side & 1) ? name.c_str() : "", (side & 2) ? name.c_str() : ""); + if (mask0 & 0x02) printf("%-23s %-23s 1ST HALF = FFxx\n", (side & 1) ? name.c_str() : "", (side & 2) ? name.c_str() : ""); + if (mask0 & 0x04) printf("%-23s %-23s 1ST HALF = xx00\n", (side & 1) ? name.c_str() : "", (side & 2) ? name.c_str() : ""); + if (mask0 & 0x08) printf("%-23s %-23s 1ST HALF = xxFF\n", (side & 1) ? name.c_str() : "", (side & 2) ? name.c_str() : ""); + if (mask0 & 0x10) printf("%-23s %-23s 2ND HALF = 00xx\n", (side & 1) ? name.c_str() : "", (side & 2) ? name.c_str() : ""); + if (mask0 & 0x20) printf("%-23s %-23s 2ND HALF = FFxx\n", (side & 1) ? name.c_str() : "", (side & 2) ? name.c_str() : ""); + if (mask0 & 0x40) printf("%-23s %-23s 2ND HALF = xx00\n", (side & 1) ? name.c_str() : "", (side & 2) ? name.c_str() : ""); + if (mask0 & 0x80) printf("%-23s %-23s 2ND HALF = xxFF\n", (side & 1) ? name.c_str() : "", (side & 2) ? name.c_str() : ""); } - if (mask0 != sizemask || mask1 != 0x00) + int usedbytes(int mode) const { - printf("%-23s %-23s ",side ? "" : file->name,side ? file->name : ""); - for (int i = 0; i < 24; i++) + switch (mode) { - if (file->size <= (1<<(23-i))) printf(" "); - else if ((mask0 & 0x800000) == 0) printf("1"); - else if (mask1 & 0x800000) printf("0"); - else printf("x"); - mask0 <<= 1; - mask1 <<= 1; + case MODE_A: + case MODE_NIB1: + case MODE_NIB2: + return size; + case MODE_12: + case MODE_22: + case MODE_E: + case MODE_O: + return size / 2; + case MODE_14: + case MODE_24: + case MODE_34: + case MODE_44: + case MODE_E12: + case MODE_O12: + case MODE_E22: + case MODE_O22: + return size / 4; + default: + return 0; } - printf(" = 0x00\n"); - - return; } - mask0 = 0xff; - for (unsigned i = 0; i < file->size/4 && mask0 != 0x00; i++) + void basemultmask(int mode, int &base, int &mult, int &mask) const { - if (file->buf[ 2*i ] != 0x00) mask0 &= ~0x01; - if (file->buf[ 2*i ] != 0xff) mask0 &= ~0x02; - if (file->buf[ 2*i+1] != 0x00) mask0 &= ~0x04; - if (file->buf[ 2*i+1] != 0xff) mask0 &= ~0x08; - if (file->buf[file->size/2 + 2*i ] != 0x00) mask0 &= ~0x10; - if (file->buf[file->size/2 + 2*i ] != 0xff) mask0 &= ~0x20; - if (file->buf[file->size/2 + 2*i+1] != 0x00) mask0 &= ~0x40; - if (file->buf[file->size/2 + 2*i+1] != 0xff) mask0 &= ~0x80; - } - - if (mask0 & 0x01) printf("%-23s %-23s 1ST HALF = 00xx\n",side ? "" : file->name,side ? file->name : ""); - if (mask0 & 0x02) printf("%-23s %-23s 1ST HALF = FFxx\n",side ? "" : file->name,side ? file->name : ""); - if (mask0 & 0x04) printf("%-23s %-23s 1ST HALF = xx00\n",side ? "" : file->name,side ? file->name : ""); - if (mask0 & 0x08) printf("%-23s %-23s 1ST HALF = xxFF\n",side ? "" : file->name,side ? file->name : ""); - if (mask0 & 0x10) printf("%-23s %-23s 2ND HALF = 00xx\n",side ? "" : file->name,side ? file->name : ""); - if (mask0 & 0x20) printf("%-23s %-23s 2ND HALF = FFxx\n",side ? "" : file->name,side ? file->name : ""); - if (mask0 & 0x40) printf("%-23s %-23s 2ND HALF = xx00\n",side ? "" : file->name,side ? file->name : ""); - if (mask0 & 0x80) printf("%-23s %-23s 2ND HALF = xxFF\n",side ? "" : file->name,side ? file->name : ""); -} - + mult = 1; + if (mode >= MODE_E) + mult = 2; -static int usedbytes(const fileinfo *file,int mode) -{ - switch (mode) - { - case MODE_A: - case MODE_NIB1: - case MODE_NIB2: - return file->size; - case MODE_12: - case MODE_22: - case MODE_E: - case MODE_O: - return file->size / 2; - case MODE_14: - case MODE_24: - case MODE_34: - case MODE_44: - case MODE_E12: - case MODE_O12: - case MODE_E22: - case MODE_O22: - return file->size / 4; - default: - return 0; + switch (mode) + { + case MODE_A: + case MODE_12: + case MODE_14: + case MODE_E: + case MODE_E12: + base = 0; mask = 0xff; break; + case MODE_NIB1: + base = 0; mask = 0x0f; break; + case MODE_NIB2: + base = 0; mask = 0xf0; break; + case MODE_O: + case MODE_O12: + base = 1; mask = 0xff; break; + case MODE_22: + case MODE_E22: + base = size / 2; mask = 0xff; break; + case MODE_O22: + base = 1 + size / 2; mask = 0xff; break; + case MODE_24: + base = size / 4; mask = 0xff; break; + case MODE_34: + base = 2*size / 4; mask = 0xff; break; + case MODE_44: + base = 3*size / 4; mask = 0xff; break; + } } -} -static void basemultmask(const fileinfo *file,int mode,int *base,int *mult,int *mask) -{ - *mult = 1; - if (mode >= MODE_E) *mult = 2; - - switch (mode) + float compare(const fileinfo &file2, int mode1, int mode2) const { - case MODE_A: - case MODE_12: - case MODE_14: - case MODE_E: - case MODE_E12: - *base = 0; *mask = 0xff; break; - case MODE_NIB1: - *base = 0; *mask = 0x0f; break; - case MODE_NIB2: - *base = 0; *mask = 0xf0; break; - case MODE_O: - case MODE_O12: - *base = 1; *mask = 0xff; break; - case MODE_22: - case MODE_E22: - *base = file->size / 2; *mask = 0xff; break; - case MODE_O22: - *base = 1 + file->size / 2; *mask = 0xff; break; - case MODE_24: - *base = file->size / 4; *mask = 0xff; break; - case MODE_34: - *base = 2*file->size / 4; *mask = 0xff; break; - case MODE_44: - *base = 3*file->size / 4; *mask = 0xff; break; - } -} + if (!buf || !file2.buf) + return 0.0; -static float filecompare(const fileinfo *file1,const fileinfo *file2,int mode1,int mode2) -{ - int i; - int match = 0; - int size1,size2; - int base1=0,base2=0,mult1=0,mult2=0,mask1=0,mask2=0; - - - if (file1->buf == nullptr || file2->buf == nullptr) return 0.0; + int const size1 = usedbytes(mode1); + int const size2 = file2.usedbytes(mode2); - size1 = usedbytes(file1,mode1); - size2 = usedbytes(file2,mode2); + if (size1 != size2) + return 0.0; - if (size1 != size2) return 0.0; + int base1=0, base2=0, mult1=0, mult2=0, mask1=0, mask2=0; + basemultmask(mode1, base1, mult1, mask1); + file2.basemultmask(mode2, base2, mult2, mask2); - basemultmask(file1,mode1,&base1,&mult1,&mask1); - basemultmask(file2,mode2,&base2,&mult2,&mask2); - - if (mask1 == mask2) - { - if (mask1 == 0xff) + int match = 0; + if (mask1 == mask2) { - /* normal compare */ - for (i = 0;i < size1;i++) - if (file1->buf[base1 + mult1 * i] == file2->buf[base2 + mult2 * i]) match++; - } - else - { - /* nibble compare, abort if other half is not empty */ - for (i = 0;i < size1;i++) + if (mask1 == 0xff) + { + // normal compare + for (int i = 0; i < size1; i++) + if (buf[base1 + mult1 * i] == file2.buf[base2 + mult2 * i]) match++; + } + else { - if (((file1->buf[base1 + mult1 * i] & ~mask1) != (0x00 & ~mask1) && - (file1->buf[base1 + mult1 * i] & ~mask1) != (0xff & ~mask1)) || - ((file2->buf[base1 + mult1 * i] & ~mask2) != (0x00 & ~mask2) && - (file2->buf[base1 + mult1 * i] & ~mask2) != (0xff & ~mask2))) + // nibble compare, abort if other half is not empty + for (int i = 0; i < size1; i++) { - match = 0; - break; + if (((buf[base1 + mult1 * i] & ~mask1) != (0x00 & ~mask1) && + (buf[base1 + mult1 * i] & ~mask1) != (0xff & ~mask1)) || + ((file2.buf[base1 + mult1 * i] & ~mask2) != (0x00 & ~mask2) && + (file2.buf[base1 + mult1 * i] & ~mask2) != (0xff & ~mask2))) + { + match = 0; + break; + } + if ((buf[base1 + mult1 * i] & mask1) == (file2.buf[base2 + mult2 * i] & mask2)) match++; } - if ((file1->buf[base1 + mult1 * i] & mask1) == (file2->buf[base2 + mult2 * i] & mask2)) match++; } } - } - return (float)match / size1; -} + return float(match) / size1; + } + void readfile(const char *path) + { + std::string fullname(path ? path : ""); + util::path_append(fullname, name); -static void readfile(const char *path,fileinfo *file) -{ - osd_file::error filerr; - uint64_t filesize; - uint32_t actual; - char fullname[256]; - osd_file::ptr f; + buf.reset(new (std::nothrow) unsigned char [size]); + if (!buf) + { + printf("%s: out of memory!\n", name.c_str()); + return; + } - if (path) - { - char delim[2] = { PATH_DELIM, '\0' }; - strcpy(fullname,path); - strcat(fullname,delim); - } - else fullname[0] = 0; - strcat(fullname,file->name); + std::error_condition filerr; + osd_file::ptr f; + uint64_t filesize; - if ((file->buf = (unsigned char *)malloc(file->size)) == nullptr) - { - printf("%s: out of memory!\n",file->name); - return; - } + filerr = osd_file::open(fullname, OPEN_FLAG_READ, f, filesize); + if (filerr) + { + printf("%s: error %s\n", fullname.c_str(), filerr.message().c_str()); + return; + } - filerr = osd_file::open(fullname, OPEN_FLAG_READ, f, filesize); - if (filerr != osd_file::error::NONE) - { - printf("%s: error %d\n", fullname, int(filerr)); - return; + uint32_t actual; + filerr = f->read(buf.get(), 0, size, actual); + if (filerr) + { + printf("%s: error %s\n", fullname.c_str(), filerr.message().c_str()); + return; + } } - filerr = f->read(file->buf, 0, file->size, actual); - if (filerr != osd_file::error::NONE) + void free() { - printf("%s: error %d\n", fullname, int(filerr)); - return; + buf.reset(); } -} - +}; -static void freefile(fileinfo *file) -{ - free(file->buf); - file->buf = nullptr; -} +static fileinfo files[2][MAX_FILES]; +static float matchscore[MAX_FILES][MAX_FILES][TOTAL_MODES][TOTAL_MODES]; -static void printname(const fileinfo *file1,const fileinfo *file2,float score,int mode1,int mode2) +static void printname(const fileinfo *file1, const fileinfo *file2, float score, int mode1, int mode2) { - printf("%-12s %s %-12s %s ",file1 ? file1->name : "",modenames[mode1],file2 ? file2->name : "",modenames[mode2]); + printf( + "%-12s %s %-12s %s ", + file1 ? file1->name.c_str() : "", + modenames[mode1], + file2 ? file2->name.c_str() : "", + modenames[mode2]); if (score == 0.0f) printf("NO MATCH\n"); else if (score == 1.0f) printf("IDENTICAL\n"); - else printf("%3.6f%%\n",(double) (score*100)); + else printf("%3.6f%%\n", double(score*100)); } @@ -483,24 +490,23 @@ static int load_files(int i, int *found, const char *path) while ((d = dir->read()) != nullptr) { const char *d_name = d->name; - char buf[255+1]; + const std::string buf(util::path_concat(path, d_name)); // FIXME: is this even used for anything? - sprintf(buf, "%s%c%s", path, PATH_DELIM, d_name); if (d->type == osd::directory::entry::entry_type::FILE) { uint64_t size = d->size; while (size && (size & 1) == 0) size >>= 1; //if (size & ~1) - // printf("%-23s %-23s ignored (not a ROM)\n",i ? "" : d_name,i ? d_name : ""); + // printf("%-23s %-23s ignored (not a ROM)\n", i ? "" : d_name, i ? d_name : ""); //else { - strcpy(files[i][found[i]].name,d_name); + files[i][found[i]].name = d_name; files[i][found[i]].size = d->size; - readfile(path,&files[i][found[i]]); + files[i][found[i]].readfile(path); files[i][found[i]].listed = 0; if (found[i] >= MAX_FILES) { - printf("%s: max of %d files exceeded\n",path,MAX_FILES); + printf("%s: max of %d files exceeded\n", path, MAX_FILES); break; } found[i]++; @@ -509,15 +515,13 @@ static int load_files(int i, int *found, const char *path) } dir.reset(); } - - /* if not, try to open as a ZIP file */ else { + /* if not, try to open as a ZIP file */ util::archive_file::ptr zip; /* wasn't a directory, so try to open it as a zip file */ - if ((util::archive_file::open_zip(path, zip) != util::archive_file::error::NONE) && - (util::archive_file::open_7z(path, zip) != util::archive_file::error::NONE)) + if (util::archive_file::open_zip(path, zip) && util::archive_file::open_7z(path, zip)) { printf("Error, cannot open zip file '%s' !\n", path); return 1; @@ -539,26 +543,29 @@ static int load_files(int i, int *found, const char *path) } else { - fileinfo *file = &files[i][found[i]]; + fileinfo &file = files[i][found[i]]; const char *delim = strrchr(zip->current_name().c_str(), '/'); if (delim) - strcpy (file->name,delim+1); + file.name = delim + 1; else - strcpy(file->name,zip->current_name().c_str()); - file->size = zip->current_uncompressed_length(); - if ((file->buf = (unsigned char *)malloc(file->size)) == nullptr) - printf("%s: out of memory!\n",file->name); + file.name = zip->current_name(); + file.size = zip->current_uncompressed_length(); + file.buf.reset(new (std::nothrow) unsigned char [file.size]); + if (!file.buf) + { + printf("%s: out of memory!\n", file.name.c_str()); + } else { - if (zip->decompress(file->buf, file->size) != util::archive_file::error::NONE) + if (zip->decompress(file.buf.get(), file.size)) { - free(file->buf); - file->buf = nullptr; + printf("%s: Decompression failed\n", file.name.c_str()); + file.free(); } } - file->listed = 0; + file.listed = 0; if (found[i] >= MAX_FILES) { printf("%s: max of %d files exceeded\n",path,MAX_FILES); @@ -576,29 +583,31 @@ int CLIB_DECL main(int argc,char *argv[]) { int err; int total_modes = MODE_NIB2; /* by default, use only MODE_A, MODE_NIB1 and MODE_NIB2 */ + bool all_hashes = false; - if (argc >= 2 && strcmp(argv[1],"-d") == 0) + while (argc >= 2) { + if (strcmp(argv[1], "-d") == 0) + total_modes = TOTAL_MODES; + else if (strcmp(argv[1], "-h") == 0) + all_hashes = true; + else + break; argc--; argv++; - total_modes = TOTAL_MODES; } if (argc < 2) { - printf("usage: romcmp [-d] [dir1 | zip1] [dir2 | zip2]\n"); + printf("usage: romcmp [-d] [-h] [dir1 | zip1] [dir2 | zip2]\n"); printf("-d enables a slower, more comprehensive comparison.\n"); + printf("-h prints hashes and sums for all files.\n"); return 0; } { - int found[2]; - int i,j,mode1,mode2; - int besti,bestj; - - - found[0] = found[1] = 0; - for (i = 0;i < 2;i++) + int found[2] = { 0, 0 }; + for (int i = 0; i < 2; i++) { if (argc > i+1) { @@ -613,28 +622,26 @@ int CLIB_DECL main(int argc,char *argv[]) else printf("%d files\n",found[0]); - for (i = 0;i < found[0];i++) - { - checkintegrity(&files[0][i],0); - } - - for (j = 0;j < found[1];j++) + for (int i = 0; i < 2; i++) { - checkintegrity(&files[1][j],1); + for (int j = 0; j < found[i]; j++) + { + files[i][j].checkintegrity(1 << i, all_hashes); + } } if (argc < 3) { - /* find duplicates in one dir */ - for (i = 0;i < found[0];i++) + // find duplicates in one dir + for (int i = 0;i < found[0];i++) { - for (j = i+1;j < found[0];j++) + for (int j = i+1;j < found[0];j++) { - for (mode1 = 0;mode1 < total_modes;mode1++) + for (int mode1 = 0;mode1 < total_modes;mode1++) { - for (mode2 = 0;mode2 < total_modes;mode2++) + for (int mode2 = 0;mode2 < total_modes;mode2++) { - if (filecompare(&files[0][i],&files[0][j],mode1,mode2) == 1.0f) + if (files[0][i].compare(files[0][j],mode1,mode2) == 1.0f) printname(&files[0][i],&files[0][j],1.0,mode1,mode2); } } @@ -643,40 +650,38 @@ int CLIB_DECL main(int argc,char *argv[]) } else { - /* compare two dirs */ - for (i = 0;i < found[0];i++) + // compare two dirs + for (int i = 0;i < found[0];i++) { - for (j = 0;j < found[1];j++) + for (int j = 0;j < found[1];j++) { fprintf(stderr,"%2d%%\r",100*(i*found[1]+j)/(found[0]*found[1])); - for (mode1 = 0;mode1 < total_modes;mode1++) + for (int mode1 = 0;mode1 < total_modes;mode1++) { - for (mode2 = 0;mode2 < total_modes;mode2++) + for (int mode2 = 0;mode2 < total_modes;mode2++) { - matchscore[i][j][mode1][mode2] = filecompare(&files[0][i],&files[1][j],mode1,mode2); + matchscore[i][j][mode1][mode2] = files[0][i].compare(files[1][j],mode1,mode2); } } } } fprintf(stderr," \r"); + int besti; do { - float bestscore; - int bestmode1,bestmode2; - besti = -1; - bestj = -1; - bestscore = 0.0; - bestmode1 = bestmode2 = -1; + int bestj = -1; + float bestscore = 0.0; + int bestmode1 = -1, bestmode2 = -1; - for (mode1 = 0;mode1 < total_modes;mode1++) + for (int mode1 = 0;mode1 < total_modes;mode1++) { - for (mode2 = 0;mode2 < total_modes;mode2++) + for (int mode2 = 0;mode2 < total_modes;mode2++) { - for (i = 0;i < found[0];i++) + for (int i = 0;i < found[0];i++) { - for (j = 0;j < found[1];j++) + for (int j = 0;j < found[1];j++) { if (matchscore[i][j][mode1][mode2] > bestscore || (matchscore[i][j][mode1][mode2] == 1.0f && mode2 == 0 && bestmode2 > 0)) @@ -703,17 +708,17 @@ int CLIB_DECL main(int argc,char *argv[]) matchscore[besti][bestj][bestmode1][bestmode2] = 0.0; /* remove all matches using the same sections with a worse score */ - for (j = 0;j < found[1];j++) + for (int j = 0;j < found[1];j++) { - for (mode2 = 0;mode2 < total_modes;mode2++) + for (int mode2 = 0;mode2 < total_modes;mode2++) { if (matchscore[besti][j][bestmode1][mode2] < bestscore) matchscore[besti][j][bestmode1][mode2] = 0.0; } } - for (i = 0;i < found[0];i++) + for (int i = 0;i < found[0];i++) { - for (mode1 = 0;mode1 < total_modes;mode1++) + for (int mode1 = 0;mode1 < total_modes;mode1++) { if (matchscore[i][bestj][mode1][bestmode2] < bestscore) matchscore[i][bestj][mode1][bestmode2] = 0.0; @@ -722,49 +727,50 @@ int CLIB_DECL main(int argc,char *argv[]) /* remove all matches using incompatible sections */ compatiblemodes(bestmode1,&start,&end); - for (j = 0;j < found[1];j++) + for (int j = 0;j < found[1];j++) { - for (mode2 = 0;mode2 < total_modes;mode2++) + for (int mode2 = 0;mode2 < total_modes;mode2++) { - for (mode1 = 0;mode1 < start;mode1++) + for (int mode1 = 0;mode1 < start;mode1++) matchscore[besti][j][mode1][mode2] = 0.0; - for (mode1 = end+1;mode1 < total_modes;mode1++) + for (int mode1 = end+1;mode1 < total_modes;mode1++) matchscore[besti][j][mode1][mode2] = 0.0; } } compatiblemodes(bestmode2,&start,&end); - for (i = 0;i < found[0];i++) + for (int i = 0;i < found[0];i++) { - for (mode1 = 0;mode1 < total_modes;mode1++) + for (int mode1 = 0;mode1 < total_modes;mode1++) { - for (mode2 = 0;mode2 < start;mode2++) + for (int mode2 = 0;mode2 < start;mode2++) matchscore[i][bestj][mode1][mode2] = 0.0; - for (mode2 = end+1;mode2 < total_modes;mode2++) + for (int mode2 = end+1;mode2 < total_modes;mode2++) matchscore[i][bestj][mode1][mode2] = 0.0; } } } - } while (besti != -1); + } + while (besti != -1); - for (i = 0;i < found[0];i++) + for (int i = 0;i < found[0];i++) { if (files[0][i].listed == 0) printname(&files[0][i],nullptr,0.0,0,0); } - for (i = 0;i < found[1];i++) + for (int i = 0;i < found[1];i++) { if (files[1][i].listed == 0) printname(nullptr,&files[1][i],0.0,0,0); } } - for (i = 0;i < found[0];i++) + for (int i = 0;i < found[0];i++) { - freefile(&files[0][i]); + files[0][i].free(); } - for (i = 0;i < found[1];i++) + for (int i = 0;i < found[1];i++) { - freefile(&files[1][i]); + files[1][i].free(); } } diff --git a/src/tools/split.cpp b/src/tools/split.cpp index 4ef18b6ad06..5668e6e254c 100644 --- a/src/tools/split.cpp +++ b/src/tools/split.cpp @@ -8,17 +8,21 @@ ****************************************************************************/ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <assert.h> #include "corefile.h" #include "corestr.h" -#include "sha1.h" +#include "hashing.h" + +#include <cassert> +#include <cctype> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <tuple> +#include <type_traits> #define DEFAULT_SPLIT_SIZE 100 #define MAX_PARTS 1000 +#define SHA1_DIGEST_SIZE 20 @@ -32,24 +36,27 @@ 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) { - char expanded[SHA1_DIGEST_SIZE * 2]; - uint8_t sha1digest[SHA1_DIGEST_SIZE]; - struct sha1_ctx sha1; - int ch; - // compute the SHA1 - sha1_init(&sha1); - sha1_update(&sha1, length, (const uint8_t *)data); - sha1_final(&sha1); - sha1_digest(&sha1, sizeof(sha1digest), sha1digest); + util::sha1_creator sha1; + 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 - for (ch = 0; ch < SHA1_DIGEST_SIZE; ch++) + char expanded[sizeof(sha1digest.m_raw) * 2]; + for (int ch = 0; ch < sizeof(sha1digest.m_raw); ch++) { - expanded[ch * 2 + 0] = "0123456789ABCDEF"[sha1digest[ch] >> 4]; - expanded[ch * 2 + 1] = "0123456789ABCDEF"[sha1digest[ch] & 15]; + expanded[ch * 2 + 0] = "0123456789ABCDEF"[sha1digest.m_raw[ch] >> 4]; + expanded[ch * 2 + 1] = "0123456789ABCDEF"[sha1digest.m_raw[ch] & 15]; } // copy it to the buffer @@ -69,7 +76,7 @@ static int split_file(const char *filename, const char *basename, uint32_t split void *splitbuffer = nullptr; int index, partnum; uint64_t totallength; - osd_file::error filerr; + std::error_condition filerr; int error = 1; // convert split size to MB @@ -82,20 +89,24 @@ static int split_file(const char *filename, const char *basename, uint32_t split // open the file for read filerr = util::core_file::open(filename, OPEN_FLAG_READ, infile); - if (filerr != osd_file::error::NONE) + if (filerr) { fprintf(stderr, "Fatal error: unable to open file '%s'\n", filename); goto cleanup; } // get the total length - totallength = infile->size(); + if (infile->length(totallength)) + { + fprintf(stderr, "Fatal error: unable to get length of file\n"); + goto cleanup; + } if (totallength < splitsize) { fprintf(stderr, "Fatal error: file is smaller than the split size\n"); goto cleanup; } - if ((uint64_t)splitsize * MAX_PARTS < totallength) + if ((uint64_t(splitsize) * MAX_PARTS) < totallength) { fprintf(stderr, "Fatal error: too many splits (maximum is %d)\n", MAX_PARTS); goto cleanup; @@ -120,7 +131,7 @@ static int split_file(const char *filename, const char *basename, uint32_t split // create the split file filerr = util::core_file::open(splitfilename, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_NO_BOM, splitfile); - if (filerr != osd_file::error::NONE) + if (filerr) { fprintf(stderr, "Fatal error: unable to create split file '%s'\n", splitfilename.c_str()); goto cleanup; @@ -136,12 +147,11 @@ static int split_file(const char *filename, const char *basename, uint32_t split // now iterate until done for (partnum = 0; partnum < 1000; partnum++) { - uint32_t actual, length; - printf("Reading part %d...", partnum); // read as much as we can from the file - length = infile->read(splitbuffer, splitsize); + size_t length; + std::tie(filerr, length) = read(*infile, splitbuffer, splitsize); // FIXME check error return if (length == 0) break; @@ -152,11 +162,11 @@ static int split_file(const char *filename, const char *basename, uint32_t split splitfile->printf("hash=%s file=%s.%03d\n", computedhash.c_str(), basefilename.c_str(), partnum); // compute the full filename for this guy - outfilename = string_format("%s.%03d", basename, partnum); + outfilename = util::string_format("%s.%03d", basename, partnum); // create it filerr = util::core_file::open(outfilename, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, outfile); - if (filerr != osd_file::error::NONE) + if (filerr) { printf("\n"); fprintf(stderr, "Fatal error: unable to create output file '%s'\n", outfilename.c_str()); @@ -166,8 +176,9 @@ static int split_file(const char *filename, const char *basename, uint32_t split printf(" writing %s.%03d...", basefilename.c_str(), partnum); // write the data - actual = outfile->write(splitbuffer, length); - if (actual != length) + size_t actual; + 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"); @@ -219,7 +230,7 @@ static int join_file(const char *filename, const char *outname, int write_output std::string basepath; util::core_file::ptr outfile, infile, splitfile; void *splitbuffer = nullptr; - osd_file::error filerr; + std::error_condition filerr; uint32_t splitsize; char buffer[256]; int error = 1; @@ -227,7 +238,7 @@ static int join_file(const char *filename, const char *outname, int write_output // open the file for read filerr = util::core_file::open(filename, OPEN_FLAG_READ, splitfile); - if (filerr != osd_file::error::NONE) + if (filerr) { fprintf(stderr, "Fatal error: unable to open file '%s'\n", filename); goto cleanup; @@ -239,8 +250,7 @@ static int join_file(const char *filename, const char *outname, int write_output fprintf(stderr, "Fatal error: corrupt or incomplete split file at line:\n%s\n", buffer); goto cleanup; } - outfilename.assign(buffer + 10); - strtrimspace(outfilename); + outfilename.assign(strtrimspace(buffer + 10)); // compute the base path basepath.assign(filename); @@ -268,7 +278,7 @@ static int join_file(const char *filename, const char *outname, int write_output { // don't overwrite the original! filerr = util::core_file::open(outfilename, OPEN_FLAG_READ, outfile); - if (filerr == osd_file::error::NONE) + if (!filerr) { outfile.reset(); fprintf(stderr, "Fatal error: output file '%s' already exists\n", outfilename.c_str()); @@ -277,7 +287,7 @@ static int join_file(const char *filename, const char *outname, int write_output // open the output for write filerr = util::core_file::open(outfilename, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, outfile); - if (filerr != osd_file::error::NONE) + if (filerr) { fprintf(stderr, "Fatal error: unable to create file '%s'\n", outfilename.c_str()); goto cleanup; @@ -289,8 +299,6 @@ static int join_file(const char *filename, const char *outname, int write_output // now iterate through each file while (splitfile->gets(buffer, sizeof(buffer))) { - uint32_t length, actual; - // make sure the hash and filename are in the right place if (strncmp(buffer, "hash=", 5) != 0 || strncmp(buffer + 5 + SHA1_DIGEST_SIZE * 2, " file=", 6) != 0) { @@ -298,15 +306,15 @@ static int join_file(const char *filename, const char *outname, int write_output goto cleanup; } expectedhash.assign(buffer + 5, SHA1_DIGEST_SIZE * 2); - infilename.assign(buffer + 5 + SHA1_DIGEST_SIZE * 2 + 6); - strtrimspace(infilename); + infilename.assign(strtrimspace(buffer + 5 + SHA1_DIGEST_SIZE * 2 + 6)); printf(" Reading file '%s'...", infilename.c_str()); // read the file's contents infilename.insert(0, basepath); + size_t length; filerr = util::core_file::load(infilename.c_str(), &splitbuffer, length); - if (filerr != osd_file::error::NONE) + if (filerr) { printf("\n"); fprintf(stderr, "Fatal error: unable to load file '%s'\n", infilename.c_str()); @@ -329,8 +337,9 @@ static int join_file(const char *filename, const char *outname, int write_output { printf(" writing..."); - actual = outfile->write(splitbuffer, length); - if (actual != length) + size_t actual; + 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/src2html.cpp b/src/tools/src2html.cpp deleted file mode 100644 index 32a21de065e..00000000000 --- a/src/tools/src2html.cpp +++ /dev/null @@ -1,905 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Aaron Giles -/*************************************************************************** - - MAME source code to HTML converter - -**************************************************************************** - - Template file format: - - <html header> - <!--PATH--> = insert path - <!--CONTENT--> = insert content - <html footer> - -***************************************************************************/ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <assert.h> -#include "osdcore.h" -#include "corestr.h" -#include "corefile.h" - - -/*************************************************************************** - CONSTANTS & DEFINES -***************************************************************************/ - -#define PREPROC_CLASS "preproc" -#define KEYWORD_CLASS "keyword" -#define CUSTOM_CLASS "custom" - - - -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ - -enum file_type -{ - FILE_TYPE_INVALID, - FILE_TYPE_C, - FILE_TYPE_MAKE, - FILE_TYPE_XML, - FILE_TYPE_TEXT -}; - - -struct ext_to_type -{ - const char * extension; - file_type type; -}; - - -struct token_entry -{ - const char * token; - const char * color; -}; - - -struct include_path -{ - include_path * next; - std::string path; -}; - - -struct list_entry -{ - list_entry * next; - std::string name; -}; - - - -/*************************************************************************** - GLOBAL VARIABLES -***************************************************************************/ - -static include_path *incpaths; - -static const ext_to_type extension_lookup[] = -{ - { ".c", FILE_TYPE_C }, - { ".h", FILE_TYPE_C }, - { ".lst", FILE_TYPE_C }, - { ".mak", FILE_TYPE_MAKE }, - { "makefile", FILE_TYPE_MAKE }, - { ".lay", FILE_TYPE_XML }, - { ".xml", FILE_TYPE_XML }, - { ".txt", FILE_TYPE_TEXT }, -}; - - -static const token_entry dummy_token_table[] = -{ - { nullptr, KEYWORD_CLASS } -}; - - -static const token_entry c_token_table[] = -{ - { "#define", PREPROC_CLASS }, - { "#elif", PREPROC_CLASS }, - { "#else", PREPROC_CLASS }, - { "#endif", PREPROC_CLASS }, - { "#error", PREPROC_CLASS }, - { "#if", PREPROC_CLASS }, - { "#ifdef", PREPROC_CLASS }, - { "#ifndef", PREPROC_CLASS }, - { "#include", PREPROC_CLASS }, - { "#line", PREPROC_CLASS }, - { "#pragma", PREPROC_CLASS }, - { "#undef", PREPROC_CLASS }, - - { "auto", KEYWORD_CLASS }, - { "bool", KEYWORD_CLASS }, - { "break", KEYWORD_CLASS }, - { "case", KEYWORD_CLASS }, - { "catch", KEYWORD_CLASS }, - { "char", KEYWORD_CLASS }, - { "class", KEYWORD_CLASS }, - { "const", KEYWORD_CLASS }, - { "const_cast", KEYWORD_CLASS }, - { "continue", KEYWORD_CLASS }, - { "default", KEYWORD_CLASS }, - { "delete", KEYWORD_CLASS }, - { "do", KEYWORD_CLASS }, - { "double", KEYWORD_CLASS }, - { "dynamic_cast", KEYWORD_CLASS }, - { "else", KEYWORD_CLASS }, - { "enum", KEYWORD_CLASS }, - { "explicit", KEYWORD_CLASS }, - { "export", KEYWORD_CLASS }, - { "extern", KEYWORD_CLASS }, - { "false", KEYWORD_CLASS }, - { "float", KEYWORD_CLASS }, - { "for", KEYWORD_CLASS }, - { "friend", KEYWORD_CLASS }, - { "goto", KEYWORD_CLASS }, - { "if", KEYWORD_CLASS }, - { "inline", KEYWORD_CLASS }, - { "int", KEYWORD_CLASS }, - { "long", KEYWORD_CLASS }, - { "mutable", KEYWORD_CLASS }, - { "namespace", KEYWORD_CLASS }, - { "new", KEYWORD_CLASS }, - { "operator", KEYWORD_CLASS }, - { "private", KEYWORD_CLASS }, - { "protected", KEYWORD_CLASS }, - { "public", KEYWORD_CLASS }, - { "register", KEYWORD_CLASS }, - { "reinterpret_cast", KEYWORD_CLASS }, - { "return", KEYWORD_CLASS }, - { "short", KEYWORD_CLASS }, - { "signed", KEYWORD_CLASS }, - { "sizeof", KEYWORD_CLASS }, - { "static", KEYWORD_CLASS }, - { "static_cast", KEYWORD_CLASS }, - { "struct", KEYWORD_CLASS }, - { "switch", KEYWORD_CLASS }, - { "template", KEYWORD_CLASS }, - { "this", KEYWORD_CLASS }, - { "throw", KEYWORD_CLASS }, - { "true", KEYWORD_CLASS }, - { "try", KEYWORD_CLASS }, - { "typedef", KEYWORD_CLASS }, - { "typeid", KEYWORD_CLASS }, - { "typename", KEYWORD_CLASS }, - { "union", KEYWORD_CLASS }, - { "unsigned", KEYWORD_CLASS }, - { "virtual", KEYWORD_CLASS }, - { "void", KEYWORD_CLASS }, - { "volatile", KEYWORD_CLASS }, - { "wchar_t", KEYWORD_CLASS }, - { "while", KEYWORD_CLASS }, - -/* - { "INLINE", CUSTOM_CLASS }, - { "int8_t", CUSTOM_CLASS }, - { "uint8_t", CUSTOM_CLASS }, - { "int16_t", CUSTOM_CLASS }, - { "uint16_t", CUSTOM_CLASS }, - { "int32_t", CUSTOM_CLASS }, - { "uint32_t", CUSTOM_CLASS }, - { "int64_t", CUSTOM_CLASS }, - { "uint64_t", CUSTOM_CLASS }, - { "ARRAY_LENGTH", CUSTOM_CLASS }, -*/ - { nullptr, KEYWORD_CLASS } -}; - - - -/*************************************************************************** - PROTOTYPES -***************************************************************************/ - -// core output functions -static int recurse_dir(int srcrootlen, int dstrootlen, std::string &srcdir, std::string &dstdir, std::string &tempheader, std::string &tempfooter); -static int output_file(file_type type, int srcrootlen, int dstrootlen, std::string &srcfile, std::string &dstfile, bool link_to_file, std::string &tempheader, std::string &tempfooter); - -// HTML helpers -static util::core_file::ptr create_file_and_output_header(std::string &filename, std::string &templatefile, std::string &path); -static void output_footer_and_close_file(util::core_file::ptr &&file, std::string &templatefile, std::string &path); - -// path helpers -static std::string &normalized_subpath(std::string &dest, std::string &path, int start); -static void output_path_as_links(util::core_file &file, std::string &path, bool end_is_directory, bool link_to_file); -static bool find_include_file(std::string &srcincpath, int srcrootlen, int dstrootlen, std::string &srcfile, std::string &dstfile, std::string &filename); - - - -/*************************************************************************** - MAIN -***************************************************************************/ - -/*------------------------------------------------- - main - main entry point --------------------------------------------------*/ - -void usage(const char *argv0) -{ - fprintf(stderr, "Usage:\n%s <srcroot> <destroot> <template.html> [-Iincpath [-Iincpath [...]]]\n", argv0); - exit(1); -} - -int main(int argc, char *argv[]) -{ - // loop over arguments - include_path **incpathhead = &incpaths; - std::string srcdir, dstdir, tempfilename, tempheader, tempfooter; - int unadorned = 0; - for (int argnum = 1; argnum < argc; argnum++) - { - char *arg = argv[argnum]; - - // include path? - if (arg[0] == '-' && arg[1] == 'I') - { - *incpathhead = new include_path; - if (*incpathhead != nullptr) - { - (*incpathhead)->next = nullptr; - strreplacechr((*incpathhead)->path.assign(&arg[2]), '/', PATH_SEPARATOR[0]); - incpathhead = &(*incpathhead)->next; - } - } - - // other parameter - else if (arg[0] != '-' && unadorned == 0) - { - srcdir.assign(arg); - unadorned++; - } - else if (arg[0] != '-' && unadorned == 1) - { - dstdir.assign(arg); - unadorned++; - } - else if (arg[0] != '-' && unadorned == 2) - { - tempfilename.assign(arg); - unadorned++; - } - else - usage(argv[0]); - } - - // make sure we got 3 parameters - if (srcdir.length() == 0 || dstdir.length() == 0 || tempfilename.length() == 0) - usage(argv[0]); - - // read the template file into an std::string - uint32_t bufsize; - void *buffer; - if (util::core_file::load(tempfilename.c_str(), &buffer, bufsize) == osd_file::error::NONE) - { - tempheader.assign((const char *)buffer, bufsize); - free(buffer); - } - - // verify the template - if (tempheader.length() == 0) - { - fprintf(stderr, "Unable to read template file\n"); - return 1; - } - int result = tempheader.find("<!--CONTENT-->"); - if (result == -1) - { - fprintf(stderr, "Template is missing a <!--CONTENT--> marker\n"); - return 1; - } - tempfooter.assign(tempheader).erase(0, result + 14); - tempheader.erase(result); - - // recurse over subdirectories - return recurse_dir(srcdir.length(), dstdir.length(), srcdir, dstdir, tempheader, tempfooter); -} - - - -/*************************************************************************** - CORE OUTPUT FUNCTIONS -***************************************************************************/ - -static int compare_list_entries(const void *p1, const void *p2) -{ - const list_entry *entry1 = *(const list_entry **)p1; - const list_entry *entry2 = *(const list_entry **)p2; - return entry1->name.compare(entry2->name); -} - - -/*------------------------------------------------- - recurse_dir - recurse through a directory --------------------------------------------------*/ - -static int recurse_dir(int srcrootlen, int dstrootlen, std::string &srcdir, std::string &dstdir, std::string &tempheader, std::string &tempfooter) -{ - static const osd::directory::entry::entry_type typelist[] = { osd::directory::entry::entry_type::DIR, osd::directory::entry::entry_type::FILE }; - - // extract a normalized subpath - std::string srcdir_subpath; - normalized_subpath(srcdir_subpath, srcdir, srcrootlen + 1); - - // create an index file - std::string indexname; - indexname = string_format("%s%c%s", dstdir.c_str(), PATH_SEPARATOR[0], "index.html"); - util::core_file::ptr indexfile = create_file_and_output_header(indexname, tempheader, srcdir_subpath); - - // output the directory navigation - indexfile->printf("<h3>Viewing Directory: "); - output_path_as_links(*indexfile, srcdir_subpath, true, false); - indexfile->printf("</h3>"); - - // iterate first over directories, then over files - int result = 0; - for (int entindex = 0; entindex < ARRAY_LENGTH(typelist) && result == 0; entindex++) - { - auto entry_type = typelist[entindex]; - - // open the directory and iterate through it - auto dir = osd::directory::open(srcdir.c_str()); - if (dir == nullptr) - { - result = 1; - break; - } - - // build up the list of files - const osd::directory::entry *entry; - int found = 0; - list_entry *list = nullptr; - while ((entry = dir->read()) != nullptr) - if (entry->type == entry_type && entry->name[0] != '.') - { - auto lentry = new list_entry; - lentry->name.assign(entry->name); - lentry->next = list; - list = lentry; - found++; - } - - // close the directory - dir.reset(); - - // skip if nothing found - if (found == 0) - continue; - - // allocate memory for sorting - auto listarray = new list_entry *[found]; - found = 0; - for (list_entry *curlist = list; curlist != nullptr; curlist = curlist->next) - listarray[found++] = curlist; - - // sort the list - qsort(listarray, found, sizeof(listarray[0]), compare_list_entries); - - // rebuild the list - list = nullptr; - while (--found >= 0) - { - listarray[found]->next = list; - list = listarray[found]; - } - delete[] listarray; - - // iterate through each file - for (list_entry *curlist = list; curlist != nullptr && result == 0; curlist = curlist->next) - { - // add a header - if (curlist == list) - indexfile->printf("\t<h2>%s</h2>\n\t<ul>\n", (entry_type == osd::directory::entry::entry_type::DIR) ? "Directories" : "Files"); - - // build the source filename - std::string srcfile; - srcfile = string_format("%s%c%s", srcdir.c_str(), PATH_SEPARATOR[0], curlist->name.c_str()); - - // if we have a file, output it - std::string dstfile; - if (entry_type == osd::directory::entry::entry_type::FILE) - { - // make sure we care, first - file_type type = FILE_TYPE_INVALID; - for (auto & elem : extension_lookup) - if (core_filename_ends_with(curlist->name, elem.extension)) - { - type = elem.type; - break; - } - - // if we got a valid file, process it - if (type != FILE_TYPE_INVALID) - { - dstfile = string_format("%s%c%s.html", dstdir.c_str(), PATH_SEPARATOR[0], curlist->name.c_str()); - if (indexfile != nullptr) - indexfile->printf("\t<li><a href=\"%s.html\">%s</a></li>\n", curlist->name.c_str(), curlist->name.c_str()); - result = output_file(type, srcrootlen, dstrootlen, srcfile, dstfile, srcdir.compare(dstdir) == 0, tempheader, tempfooter); - } - } - - // if we have a directory, recurse - else - { - dstfile = string_format("%s%c%s", dstdir.c_str(), PATH_SEPARATOR[0], curlist->name.c_str()); - if (indexfile != nullptr) - indexfile->printf("\t<li><a href=\"%s/index.html\">%s/</a></li>\n", curlist->name.c_str(), curlist->name.c_str()); - result = recurse_dir(srcrootlen, dstrootlen, srcfile, dstfile, tempheader, tempfooter); - } - } - - // close the list if we found some stuff - if (list != nullptr) - indexfile->printf("\t</ul>\n"); - - // free all the allocated entries - while (list != nullptr) - { - list_entry *next = list->next; - delete list; - list = next; - } - } - - if (indexfile != nullptr) - output_footer_and_close_file(std::move(indexfile), tempfooter, srcdir_subpath); - return result; -} - - -/*------------------------------------------------- - output_file - output a file, converting to - HTML --------------------------------------------------*/ - -static int output_file(file_type type, int srcrootlen, int dstrootlen, std::string &srcfile, std::string &dstfile, bool link_to_file, std::string &tempheader, std::string &tempfooter) -{ - // extract a normalized subpath - std::string srcfile_subpath; - normalized_subpath(srcfile_subpath, srcfile, srcrootlen + 1); - - fprintf(stderr, "Processing %s\n", srcfile_subpath.c_str()); - - // set some defaults - bool color_quotes = false; - const char *comment_start = ""; - const char *comment_start_esc = ""; - const char *comment_end = ""; - const char *comment_end_esc = ""; - const char *comment_inline = ""; - const char *comment_inline_esc = ""; - const char *token_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_#"; - const token_entry *token_table = dummy_token_table; - - // based on the file type, set the comment info - switch (type) - { - case FILE_TYPE_C: - color_quotes = true; - comment_start = comment_start_esc = "/*"; - comment_end = comment_end_esc = "*/"; - comment_inline = comment_inline_esc = "//"; - token_table = c_token_table; - break; - - case FILE_TYPE_MAKE: - color_quotes = true; - comment_inline = comment_inline_esc = "#"; - break; - - case FILE_TYPE_XML: - color_quotes = true; - comment_start = "<!--"; - comment_start_esc = "<!--"; - comment_end = "-->"; - comment_end_esc = "-->"; - break; - - default: - case FILE_TYPE_TEXT: - break; - } - - // make the token lookup table - bool is_token[256]; - memset(is_token, 0, sizeof(is_token)); - for (int toknum = 0; token_chars[toknum] != 0; toknum++) - is_token[(uint8_t)token_chars[toknum]] = true; - - // open the source file - util::core_file::ptr src; - if (util::core_file::open(srcfile, OPEN_FLAG_READ, src) != osd_file::error::NONE) - { - fprintf(stderr, "Unable to read file '%s'\n", srcfile.c_str()); - return 1; - } - - // open the output file - util::core_file::ptr dst = create_file_and_output_header(dstfile, tempheader, srcfile_subpath); - if (dst == nullptr) - { - fprintf(stderr, "Unable to write file '%s'\n", dstfile.c_str()); - return 1; - } - - // output the directory navigation - dst->printf("<h3>Viewing File: "); - output_path_as_links(*dst, srcfile_subpath, false, link_to_file); - dst->printf("</h3>"); - - // start with some tags - dst->printf("\t<pre class=\"source\">\n"); - - // iterate over lines in the source file - int linenum = 1; - bool in_comment = false; - char srcline[4096]; - std::ostringstream dstline; - while (src->gets(srcline, ARRAY_LENGTH(srcline)) != nullptr) - { - // start with the line number - dstline.str(""); - util::stream_format(dstline, "<span class=\"linenum\">%5d</span> ", linenum++); - - // iterate over characters in the source line - bool escape = false; - bool in_quotes = false; - bool in_inline_comment = false; - bool last_token_was_include = false; - bool last_was_token = false; - bool quotes_are_linked = false; - uint8_t curquote = 0; - int curcol = 0; - for (char *srcptr = srcline; *srcptr != 0; ) - { - uint8_t ch = *srcptr++; - - // track whether or not we are within an extended (C-style) comment - if (!in_quotes && !in_inline_comment) - { - if (!in_comment && ch == comment_start[0] && strncmp(srcptr - 1, comment_start, strlen(comment_start)) == 0) - { - util::stream_format(dstline, "<span class=\"comment\">%s", comment_start_esc); - curcol += strlen(comment_start); - srcptr += strlen(comment_start) - 1; - ch = 0; - in_comment = true; - } - else if (in_comment && ch == comment_end[0] && strncmp(srcptr - 1, comment_end, strlen(comment_end)) == 0) - { - util::stream_format(dstline, "%s</span>", comment_end_esc); - curcol += strlen(comment_end); - srcptr += strlen(comment_end) - 1; - ch = 0; - in_comment = false; - } - } - - // track whether or not we are within an inline (C++-style) comment - if (!in_quotes && !in_comment && !in_inline_comment && ch == comment_inline[0] && strncmp(srcptr - 1, comment_inline, strlen(comment_inline)) == 0) - { - util::stream_format(dstline, "<span class=\"comment\">%s", comment_inline_esc); - curcol += strlen(comment_inline); - srcptr += strlen(comment_inline) - 1; - ch = 0; - in_inline_comment = true; - } - - // if this is the start of a new token, see if we want to color it - if (!in_quotes && !in_comment && !in_inline_comment && !last_was_token && is_token[ch]) - { - const token_entry *curtoken; - char *temp = srcptr; - int toklength; - - // find the end of the token - while (*temp != 0 && is_token[(uint8_t)*temp]) - temp++; - toklength = temp - (srcptr - 1); - - // scan the token table - last_token_was_include = false; - for (curtoken = token_table; curtoken->token != nullptr; curtoken++) - if (strncmp(srcptr - 1, curtoken->token, toklength) == 0 && strlen(curtoken->token) == toklength) - { - util::stream_format(dstline, "<span class=\"%s\">%s</span>", curtoken->color, curtoken->token); - curcol += strlen(curtoken->token); - srcptr += strlen(curtoken->token) - 1; - ch = 0; - - // look for include tokens specially - if (type == FILE_TYPE_C && strcmp(curtoken->token, "#include") == 0) - last_token_was_include = true; - break; - } - } - last_was_token = is_token[ch]; - - // if we hit a tab, expand it - if (ch == 0x09) - { - // compute how many spaces - int spaces = 4 - curcol % 4; - while (spaces--) - { - dstline.put(' '); - curcol++; - } - } - - // otherwise, copy the source character - else if (ch != 0x0a && ch != 0x0d && ch != 0) - { - // track opening quotes - if (!in_comment && !in_inline_comment && !in_quotes && (ch == '"' || ch == '\'')) - { - if (color_quotes) - util::stream_format(dstline, "<span class=\"string\">%c", ch); - else - dstline.put(ch); - in_quotes = true; - curquote = ch; - - // handle includes - if (last_token_was_include) - { - char *endquote = strchr(srcptr, ch); - if (endquote != nullptr) - { - std::string filename(srcptr, endquote - srcptr); - std::string target; - if (find_include_file(target, srcrootlen, dstrootlen, srcfile, dstfile, filename)) - { - util::stream_format(dstline, "<a href=\"%s\">", target.c_str()); - quotes_are_linked = true; - } - } - } - } - - // track closing quotes - else if (!in_comment && !in_inline_comment && in_quotes && (ch == curquote) && !escape) - { - if (quotes_are_linked) - dstline << "</a>"; - if (color_quotes) - util::stream_format(dstline, "%c</span>", ch); - else - dstline.put(ch); - in_quotes = false; - curquote = 0; - quotes_are_linked = false; - } - - // else just output the current character - else if (ch == '&') - dstline << "&"; - else if (ch == '<') - dstline << "<"; - else if (ch == '>') - dstline << ">"; - else - dstline.put(ch); - curcol++; - } - - // Update escape state - if (in_quotes) - escape = (ch == '\\' && type == FILE_TYPE_C) ? !escape : false; - } - - // finish inline comments - if (in_inline_comment) - { - dstline << "</span>"; - in_inline_comment = false; - } - - // append a break and move on - dstline.put('\n'); - dst->puts(dstline.str().c_str()); - } - - // close tags - dst->printf("\t</pre>\n"); - - // close the file - output_footer_and_close_file(std::move(dst), tempfooter, srcfile_subpath); - return 0; -} - - - -/*************************************************************************** - HTML OUTPUT HELPERS -***************************************************************************/ - -/*------------------------------------------------- - create_file_and_output_header - create a new - HTML file with a standard header --------------------------------------------------*/ - -static util::core_file::ptr create_file_and_output_header(std::string &filename, std::string &templatefile, std::string &path) -{ - // create the indexfile - util::core_file::ptr file; - if (util::core_file::open(filename, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS | OPEN_FLAG_NO_BOM, file) != osd_file::error::NONE) - return util::core_file::ptr(); - - // print a header - std::string modified(templatefile); - strreplace(modified, "<!--PATH-->", path.c_str()); - file->write(modified.c_str(), modified.length()); - - // return the file - return file; -} - - -/*------------------------------------------------- - output_footer_and_close_file - write a - standard footer to an HTML file and close it --------------------------------------------------*/ - -static void output_footer_and_close_file(util::core_file::ptr &&file, std::string &templatefile, std::string &path) -{ - std::string modified(templatefile); - strreplace(modified, "<!--PATH-->", path.c_str()); - file->write(modified.c_str(), modified.length()); - file.reset(); -} - - - -/*************************************************************************** - HTML OUTPUT HELPERS -***************************************************************************/ - -/*------------------------------------------------- - normalized_subpath - normalize a path to - forward slashes and extract a subpath --------------------------------------------------*/ - -static std::string &normalized_subpath(std::string &dest, std::string &path, int start) -{ - strreplacechr(dest.assign(path.substr(start, -1)),PATH_SEPARATOR[0], '/'); - return dest; -} - - -/*------------------------------------------------- - output_path_as_links - output a path as a - series of links --------------------------------------------------*/ - -static void output_path_as_links(util::core_file &file, std::string &path, bool end_is_directory, bool link_to_file) -{ - // first count how deep we are - int srcdepth = 0; - for (int slashindex = path.find_first_of('/'); slashindex != -1; slashindex = path.find_first_of('/', slashindex + 1)) - srcdepth++; - if (end_is_directory) - srcdepth++; - - // output a link to the root - file.printf("<a href=\""); - for (int depth = 0; depth < srcdepth; depth++) - file.printf("../"); - file.printf("index.html\"><root></a>/"); - - // now output links to each path up the chain - int curdepth = 0; - int lastslash = 0; - for (int slashindex = path.find_first_of('/', lastslash); slashindex != -1; slashindex = path.find_first_of('/', lastslash)) - { - std::string substr(path, lastslash, slashindex - lastslash); - - curdepth++; - file.printf("<a href=\""); - for (int depth = curdepth; depth < srcdepth; depth++) - file.printf("../"); - file.printf("index.html\">%s</a>/", substr.c_str()); - - lastslash = slashindex + 1; - } - - // and a final link to the current directory - std::string substr(path, lastslash, -1); - if (end_is_directory) - file.printf("<a href=\"index.html\">%s</a>", substr.c_str()); - else if (link_to_file) - file.printf("<a href=\"%s\">%s</a>", substr.c_str(), substr.c_str()); - else - file.printf("<a href=\"%s.html\">%s</a>", substr.c_str(), substr.c_str()); -} - - -/*------------------------------------------------- - find_include_file - find an include file --------------------------------------------------*/ - -static bool find_include_file(std::string &srcincpath, int srcrootlen, int dstrootlen, std::string &srcfile, std::string &dstfile, std::string &filename) -{ - // iterate over include paths and find the file - for (include_path *curpath = incpaths; curpath != nullptr; curpath = curpath->next) - { - // a '.' include path is specially treated - if (curpath->path.compare(".") == 0) - srcincpath.assign(srcfile.substr(0, srcfile.find_last_of(PATH_SEPARATOR[0]))); - else - srcincpath.assign(srcfile.substr(0, srcrootlen + 1)).append(curpath->path); - - // append the filename piecemeal to account for directories - int lastsepindex = 0; - int sepindex; - while ((sepindex = filename.find_first_of('/', lastsepindex)) != -1) - { - // handle .. by removing a chunk from the incpath - std::string pathpart(filename, lastsepindex, sepindex - lastsepindex); - if (pathpart.compare("..")==0) - { - sepindex = srcincpath.find_last_of(PATH_SEPARATOR[0]); - if (sepindex != -1) - srcincpath.erase(sepindex); - } - - // otherwise, append a path separator and the pathpart - else - srcincpath.append(PATH_SEPARATOR).append(pathpart); - - // advance past the previous index - lastsepindex = sepindex + 1; - } - - // now append the filename - srcincpath.append(PATH_SEPARATOR).append(filename.substr(lastsepindex, -1)); - - // see if we can open it - util::core_file::ptr testfile; - if (util::core_file::open(srcincpath, OPEN_FLAG_READ, testfile) == osd_file::error::NONE) - { - // close the file - testfile.reset(); - - // find the longest matching directory substring between the include and source file - lastsepindex = 0; - while ((sepindex = srcincpath.find_first_of(PATH_SEPARATOR[0], lastsepindex)) != -1) - { - // get substrings up to the current directory - std::string tempfile(srcfile, 0, sepindex); - std::string tempinc(srcincpath, 0, sepindex); - - // if we don't match, stop - if (tempfile.compare(tempinc)!=0) - break; - lastsepindex = sepindex + 1; - } - - // chop off the common parts of the paths - std::string tempfile(srcfile, lastsepindex, -1); - srcincpath = srcincpath.substr(lastsepindex, -1); - strreplacechr(srcincpath, PATH_SEPARATOR[0], '/'); - - // for each directory left in the filename, we need to prepend a "../" - while ((sepindex = tempfile.find_first_of(PATH_SEPARATOR[0])) != -1) - { - tempfile.erase(0, sepindex + 1); - srcincpath.insert(0, "../"); - } - srcincpath.append(".html"); - - // free the strings and return the include path - return true; - } - } - return false; -} diff --git a/src/tools/srcclean.cpp b/src/tools/srcclean.cpp index 431bc00434c..63809b57f1e 100644 --- a/src/tools/srcclean.cpp +++ b/src/tools/srcclean.cpp @@ -4,7 +4,7 @@ srcclean.cpp - Basic source code cleanear. + Basic source code cleaner. ****************************************************************************/ @@ -19,15 +19,18 @@ Known C++ limitations: * No filtering of control characters + * Will not handle raw string literals correctly * Will not produce expected output for a string continuation within a preprocessor macro, e.g this: #define MY_MACRO \ "string that \ continues" - * Will not produce expected output for a string continuation that - breaks an escape sequence, e.g. this: - "bad\\ - tbehaviour" + * Numeric literals broken by line continuations are not recognised + * Will not recognise a comment delimiter broken by multiple line + continuations. e.g. this: + /\ + \ + / preprocessor abuse Known Lua limitations: * Whitespace normalisation is applied inside long string literals @@ -36,6 +39,9 @@ may have spacing adjusted in a way that affects behaviour when uncommented + Known JSON limitations: + * Doesn't detect invalid numbers or literals + Known XML limitations: * No special handling for CDATA * No special handling for processing instructions @@ -49,7 +55,6 @@ #include "corefile.h" #include "corestr.h" -#include "osdcore.h" #include "strformat.h" #include <algorithm> @@ -101,14 +106,21 @@ protected: static constexpr char32_t HORIZONTAL_TAB = 0x0000'0009U; static constexpr char32_t LINE_FEED = 0x0000'000aU; static constexpr char32_t VERTICAL_TAB = 0x0000'000bU; + static constexpr char32_t FORM_FEED = 0x0000'000cU; + static constexpr char32_t C0_CONTROL_LAST = 0x0000'001fU; static constexpr char32_t SPACE = 0x0000'0020U; static constexpr char32_t DOUBLE_QUOTE = 0x0000'0022U; static constexpr char32_t SINGLE_QUOTE = 0x0000'0027U; + static constexpr char32_t ASTERISK = 0x0000'002aU; static constexpr char32_t HYPHEN_MINUS = 0x0000'002dU; + static constexpr char32_t SLASH = 0x0000'002fU; static constexpr char32_t QUESTION_MARK = 0x0000'003fU; static constexpr char32_t BACKSLASH = 0x0000'005cU; static constexpr char32_t BASIC_LATIN_LAST = 0x0000'007fU; static constexpr char32_t CYRILLIC_SUPPLEMENT_LAST = 0x0000'052fU; + static constexpr char32_t LINE_SEPARATOR = 0x0000'2028U; + static constexpr char32_t PARAGRAPH_SEPARATOR = 0x0000'2029U; + static constexpr char32_t SUPPLEMENTARY_FIRST = 0x0001'0000U; template <typename OutputIt> cleaner_base(OutputIt &&output, newline newline_mode, unsigned tab_width); @@ -128,7 +140,6 @@ private: static constexpr char32_t NONCHARACTER_LAST = 0x0000'fdefU; static constexpr char32_t ZERO_WIDTH_NB_SPACE = 0x0000'feffU; static constexpr char32_t REPLACEMENT_CHARACTER = 0x0000'fffdU; - static constexpr char32_t SUPPLEMENTARY_FIRST = 0x0001'0000U; static constexpr char32_t SUPPLEMENTARY_LAST = 0x0010'ffffU; static constexpr char32_t CODE_LENGTH_THRESHOLDS[6]{ @@ -176,7 +187,7 @@ private: // output state management unsigned m_output_column = 0U; - unsigned m_indent; + unsigned m_indent = 0U; unsigned m_tab_limit = std::numeric_limits<unsigned>::max(); std::vector<char32_t> m_whitespace; @@ -595,7 +606,7 @@ void cleaner_base::output_utf8(char32_t ch) void cleaner_base::commit_character(char32_t ch) { - assert(ARRAY_LENGTH(m_buffer) > m_position); + assert(std::size(m_buffer) > m_position); assert(1U <= m_code_length); assert(6U >= m_code_length); @@ -695,7 +706,7 @@ void cleaner_base::commit_character(char32_t ch) void cleaner_base::process_if_full() { - if (ARRAY_LENGTH(m_buffer) == m_position) + if (std::size(m_buffer) == m_position) { process_characters(m_buffer, m_buffer + m_position); m_position = 0U; @@ -824,8 +835,6 @@ protected: void output_character(char32_t ch); private: - static constexpr char32_t ASTERISK = 0x0000'002aU; - static constexpr char32_t SLASH = 0x0000'002fU; static constexpr char32_t UPPERCASE_FIRST = 0x0000'0041U; static constexpr char32_t UPPERCASE_B = 0x0000'0042U; static constexpr char32_t UPPERCASE_X = 0x0000'0058U; @@ -868,19 +877,19 @@ private: bool tail_is(char32_t ch) const { - return !m_tail.empty() && (m_tail.front() == ch); + return !m_tail.empty() && (m_tail.back() == ch); } void pop_tail() { if (!m_tail.empty()) - m_tail.pop_front(); + m_tail.pop_back(); } void replace_tail(char32_t ch) { assert(!m_tail.empty()); - *m_tail.begin() = ch; + m_tail.back() = ch; } void flush_tail() @@ -938,10 +947,12 @@ private: bool m_escape = false; std::deque<char32_t> m_tail; std::uint64_t m_comment_line = 0U; + bool m_broken_escape = false; char32_t m_lead_digit = 0U; unsigned m_radix = 0U; std::uint64_t m_tabs_escaped = 0U; + std::uint64_t m_broken_comment_delimiters = 0U; std::uint64_t m_line_comment_continuations = 0U; std::uint64_t m_string_continuations = 0U; std::uint64_t m_uppercase_radix = 0U; @@ -965,6 +976,7 @@ bool cpp_cleaner::affected() const return cleaner_base::affected() || m_tabs_escaped || + m_broken_comment_delimiters || m_line_comment_continuations || m_string_continuations || m_uppercase_radix || @@ -977,6 +989,8 @@ void cpp_cleaner::summarise(std::ostream &os) const cleaner_base::summarise(os); if (m_tabs_escaped) util::stream_format(os, "%1$u tab(s) escaped\n", m_tabs_escaped); + if (m_broken_comment_delimiters) + util::stream_format(os, "%1$u broken comment delimiter(s) replaced\n", m_broken_comment_delimiters); if (m_line_comment_continuations) util::stream_format(os, "%1$u line comment continuation(s) replaced\n", m_line_comment_continuations); if (m_string_continuations) @@ -994,7 +1008,6 @@ void cpp_cleaner::output_character(char32_t ch) { case parse_state::DEFAULT: case parse_state::TOKEN: - case parse_state::CHARACTER_CONSTANT: case parse_state::NUMERIC_CONSTANT: if (BASIC_LATIN_LAST < ch) { @@ -1004,28 +1017,24 @@ void cpp_cleaner::output_character(char32_t ch) break; case parse_state::COMMENT: case parse_state::LINE_COMMENT: - break; case parse_state::STRING_CONSTANT: - if (CYRILLIC_SUPPLEMENT_LAST < ch) - { - ++m_non_ascii; - ch = QUESTION_MARK; - } + case parse_state::CHARACTER_CONSTANT: break; } switch (ch) { + case HORIZONTAL_TAB: + case SPACE: + case BACKSLASH: + m_tail.emplace_back(ch); + break; default: flush_tail(); if (LINE_FEED == ch) - { cleaner_base::output_character(ch); - break; - } - case HORIZONTAL_TAB: - case SPACE: - m_tail.emplace_back(ch); + else + m_tail.emplace_back(ch); } } @@ -1085,6 +1094,13 @@ void cpp_cleaner::process_default(char32_t ch) { switch (ch) { + case LINE_FEED: + if (m_escape && tail_is(BACKSLASH)) + { + m_broken_escape = true; + return; + } + break; case DOUBLE_QUOTE: m_parse_state = parse_state::STRING_CONSTANT; break; @@ -1097,11 +1113,35 @@ void cpp_cleaner::process_default(char32_t ch) m_parse_state = parse_state::COMMENT; m_comment_line = m_input_line; set_tab_limit(); + if (m_broken_escape) + { + ++m_broken_comment_delimiters; + assert(tail_is(BACKSLASH)); + pop_tail(); + output_character(ch); + output_character(LINE_FEED); + m_escape = false; + m_broken_escape = false; + return; + } } break; case SLASH: if (m_escape) + { m_parse_state = parse_state::LINE_COMMENT; + if (m_broken_escape) + { + ++m_broken_comment_delimiters; + assert(tail_is(BACKSLASH)); + pop_tail(); + assert(tail_is(SLASH)); + pop_tail(); + output_character(LINE_FEED); + output_character(SLASH); + m_broken_escape = false; + } + } break; default: if (is_token_lead(ch)) @@ -1112,11 +1152,15 @@ void cpp_cleaner::process_default(char32_t ch) { m_parse_state = parse_state::NUMERIC_CONSTANT; m_escape = false; + m_broken_escape = false; process_numeric(ch); return; } } - m_escape = (SLASH == ch) ? !m_escape : false; + if (m_broken_escape) + output_character(LINE_FEED); + m_escape = m_escape ? ((BACKSLASH == ch) && tail_is(SLASH)) : (SLASH == ch); + m_broken_escape = false; output_character(ch); } @@ -1125,18 +1169,65 @@ void cpp_cleaner::process_comment(char32_t ch) { switch (ch) { - case SLASH: - if (m_escape) + case LINE_FEED: + if (m_escape && tail_is(BACKSLASH)) + { + m_broken_escape = true; + } + else { m_escape = false; + m_broken_escape = false; + output_character(ch); + } + break; + case SLASH: + if (m_broken_escape) + { m_parse_state = parse_state::DEFAULT; m_comment_line = 0U; + ++m_broken_comment_delimiters; + assert(tail_is(BACKSLASH)); + pop_tail(); + assert(tail_is(ASTERISK)); + pop_tail(); + output_character(LINE_FEED); + output_character(ASTERISK); output_character(ch); reset_tab_limit(); - break; } + else if (m_escape) + { + m_parse_state = parse_state::DEFAULT; + m_comment_line = 0U; + output_character(ch); + reset_tab_limit(); + } + else + { + output_character(ch); + } + m_escape = false; + m_broken_escape = false; + break; + case BACKSLASH: + if (m_broken_escape) + { + m_escape = false; + m_broken_escape = false; + output_character(LINE_FEED); + } + else if (m_escape) + { + m_escape = tail_is(ASTERISK); + } + output_character(ch); + break; default: + if (m_broken_escape) + output_character(LINE_FEED); m_escape = ASTERISK == ch; + m_broken_escape = false; output_character(ch); } } @@ -1157,6 +1248,7 @@ void cpp_cleaner::process_line_comment(char32_t ch) break; } m_parse_state = parse_state::DEFAULT; + [[fallthrough]]; default: output_character(ch); } @@ -1195,9 +1287,24 @@ void cpp_cleaner::process_text(char32_t ch) else if (tail_is(BACKSLASH)) { ++m_string_continuations; - replace_tail(DOUBLE_QUOTE); - output_character(ch); - output_character(DOUBLE_QUOTE); + if (m_escape) + { + replace_tail(DOUBLE_QUOTE); + output_character(ch); + output_character(DOUBLE_QUOTE); + } + else + { + pop_tail(); + assert(tail_is(BACKSLASH)); + pop_tail(); + output_character(DOUBLE_QUOTE); + output_character(ch); + output_character(DOUBLE_QUOTE); + output_character(BACKSLASH); + m_escape = true; + return; + } } else { @@ -1211,9 +1318,25 @@ void cpp_cleaner::process_text(char32_t ch) output_character(char32_t(std::uint8_t('v'))); break; default: - output_character(ch); - if (!m_escape && (((parse_state::STRING_CONSTANT == m_parse_state) ? DOUBLE_QUOTE : SINGLE_QUOTE) == ch)) - m_parse_state = parse_state::DEFAULT; + if (CYRILLIC_SUPPLEMENT_LAST >= ch) + { + output_character(ch); + if (!m_escape && (((parse_state::STRING_CONSTANT == m_parse_state) ? DOUBLE_QUOTE : SINGLE_QUOTE) == ch)) + m_parse_state = parse_state::DEFAULT; + } + else + { + ++m_non_ascii; + bool const supplementary(SUPPLEMENTARY_FIRST <= ch); + if (!m_escape) + output_character(BACKSLASH); + output_character(char32_t(std::uint8_t(supplementary ? 'U' : 'u'))); + for (int shift = supplementary ? 28 : 12; 0 <= shift; shift -= 4) + { + std::uint8_t const digit((ch >> shift) & 0x0fU); + output_character(std::uint8_t((10U > digit) ? '0' : ('a' - 10)) + digit); + } + } } m_escape = (BACKSLASH == ch) && !m_escape; } @@ -1245,12 +1368,14 @@ void cpp_cleaner::process_numeric(char32_t ch) case UPPERCASE_B: ++m_uppercase_radix; ch = LOWERCASE_B; + [[fallthrough]]; case LOWERCASE_B: m_radix = 2U; break; case UPPERCASE_X: ++m_uppercase_radix; ch = LOWERCASE_X; + [[fallthrough]]; case LOWERCASE_X: m_radix = 16U; break; @@ -1511,6 +1636,7 @@ void lua_cleaner::process_default(char32_t ch) m_block_line = m_input_line; m_block_level = m_long_bracket_level; m_parse_state = parse_state::LONG_STRING_CONSTANT; + [[fallthrough]]; default: m_long_bracket_level = -1; } @@ -1538,6 +1664,7 @@ void lua_cleaner::process_short_comment(char32_t ch) m_block_level = m_long_bracket_level; m_parse_state = parse_state::LONG_COMMENT; set_tab_limit(); + [[fallthrough]]; default: m_long_bracket_level = -1; } @@ -1632,6 +1759,289 @@ void lua_cleaner::process_long_string_constant(char32_t ch) /*************************************************************************** + JSON DATA CLEANER CLASS +***************************************************************************/ + +class json_cleaner : public cleaner_base +{ +public: + template <typename OutputIt> + json_cleaner(OutputIt &&output, newline newline_mode, unsigned tab_width); + + virtual bool affected() const override; + virtual void summarise(std::ostream &os) const override; + +protected: + void output_character(char32_t ch); + +private: + enum class parse_state + { + DEFAULT, + COMMENT, + LINE_COMMENT, + STRING_CONSTANT + }; + + virtual void process_characters(char32_t const *begin, char32_t const *end) override; + virtual void input_complete() override; + + void process_default(char32_t ch); + void process_comment(char32_t ch); + void process_line_comment(char32_t ch); + void process_text(char32_t ch); + + parse_state m_parse_state = parse_state::DEFAULT; + std::uint64_t m_input_line = 1U; + bool m_escape = false; + std::uint64_t m_comment_line = 0U; + + std::uint64_t m_tabs_escaped = 0U; + std::uint64_t m_newlines_escaped = 0U; + std::uint64_t m_form_feeds_escaped = 0U; + std::uint64_t m_line_separators_escaped = 0U; + std::uint64_t m_paragraph_separators_escaped = 0U; + std::uint64_t m_c0_control_escaped = 0U; + std::uint64_t m_non_ascii = 0U; +}; + + +template <typename OutputIt> +json_cleaner::json_cleaner( + OutputIt &&output, + newline newline_mode, + unsigned tab_width) + : cleaner_base(std::forward<OutputIt>(output), newline_mode, tab_width) +{ +} + + +bool json_cleaner::affected() const +{ + return + cleaner_base::affected() || + m_tabs_escaped || + m_newlines_escaped || + m_form_feeds_escaped || + m_line_separators_escaped || + m_paragraph_separators_escaped || + m_c0_control_escaped || + m_non_ascii; +} + + +void json_cleaner::summarise(std::ostream &os) const +{ + cleaner_base::summarise(os); + if (m_tabs_escaped) + util::stream_format(os, "%1$u tab(s) escaped\n", m_tabs_escaped); + if (m_newlines_escaped) + util::stream_format(os, "%1$u line feed(s) escaped\n", m_newlines_escaped); + if (m_form_feeds_escaped) + util::stream_format(os, "%1$u form feed(s) escaped\n", m_form_feeds_escaped); + if (m_line_separators_escaped) + util::stream_format(os, "%1$u line separator(s) escaped\n", m_line_separators_escaped); + if (m_paragraph_separators_escaped) + util::stream_format(os, "%1$u paragraph separator(s) escaped\n", m_paragraph_separators_escaped); + if (m_c0_control_escaped) + util::stream_format(os, "%1$u C0 control character(s) escaped\n", m_c0_control_escaped); + if (m_non_ascii) + util::stream_format(os, "%1$u non-ASCII character(s) replaced\n", m_non_ascii); +} + + +void json_cleaner::output_character(char32_t ch) +{ + switch (m_parse_state) + { + case parse_state::DEFAULT: + if (BASIC_LATIN_LAST < ch) + { + ++m_non_ascii; + ch = QUESTION_MARK; + } + break; + case parse_state::COMMENT: + case parse_state::LINE_COMMENT: + case parse_state::STRING_CONSTANT: + break; + } + + cleaner_base::output_character(ch); +} + + +void json_cleaner::process_characters(char32_t const *begin, char32_t const *end) +{ + while (begin != end) + { + char32_t const ch(*begin++); + switch (m_parse_state) + { + case parse_state::DEFAULT: + process_default(ch); + break; + case parse_state::COMMENT: + process_comment(ch); + break; + case parse_state::LINE_COMMENT: + process_line_comment(ch); + break; + case parse_state::STRING_CONSTANT: + process_text(ch); + break; + } + + if (LINE_FEED == ch) + ++m_input_line; + } +} + + +void json_cleaner::input_complete() +{ + switch (m_parse_state) + { + case parse_state::COMMENT: + throw std::runtime_error(util::string_format("unterminated multi-line comment beginning on line %1$u", m_comment_line)); + case parse_state::STRING_CONSTANT: + throw std::runtime_error(util::string_format("unterminated string literal on line %1$u", m_input_line)); + default: + break; + } +} + + +void json_cleaner::process_default(char32_t ch) +{ + switch (ch) + { + case DOUBLE_QUOTE: + m_parse_state = parse_state::STRING_CONSTANT; + break; + case ASTERISK: + if (m_escape) + { + m_parse_state = parse_state::COMMENT; + m_comment_line = m_input_line; + set_tab_limit(); + } + break; + case SLASH: + if (m_escape) + m_parse_state = parse_state::LINE_COMMENT; + break; + } + m_escape = (SLASH == ch) && !m_escape; + output_character(ch); +} + + +void json_cleaner::process_comment(char32_t ch) +{ + switch (ch) + { + case SLASH: + if (m_escape) + { + m_parse_state = parse_state::DEFAULT; + m_comment_line = 0U; + output_character(ch); + reset_tab_limit(); + } + else + { + output_character(ch); + } + m_escape = false; + break; + default: + m_escape = ASTERISK == ch; + output_character(ch); + } +} + + +void json_cleaner::process_line_comment(char32_t ch) +{ + switch (ch) + { + case LINE_FEED: + m_parse_state = parse_state::DEFAULT; + [[fallthrough]]; + default: + output_character(ch); + } +} + + +void json_cleaner::process_text(char32_t ch) +{ + switch (ch) + { + case HORIZONTAL_TAB: + ++m_tabs_escaped; + if (!m_escape) + output_character(BACKSLASH); + output_character(char32_t(std::uint8_t('t'))); + break; + case LINE_FEED: + ++m_newlines_escaped; + if (!m_escape) + output_character(BACKSLASH); + output_character(char32_t(std::uint8_t('n'))); + break; + case FORM_FEED: + ++m_form_feeds_escaped; + if (!m_escape) + output_character(BACKSLASH); + output_character(char32_t(std::uint8_t('f'))); + break; + case LINE_SEPARATOR: + ++m_line_separators_escaped; + if (!m_escape) + output_character(BACKSLASH); + output_character(char32_t(std::uint8_t('u'))); + output_character(char32_t(std::uint8_t('2'))); + output_character(char32_t(std::uint8_t('0'))); + output_character(char32_t(std::uint8_t('2'))); + output_character(char32_t(std::uint8_t('8'))); + break; + case PARAGRAPH_SEPARATOR: + ++m_paragraph_separators_escaped; + if (!m_escape) + output_character(BACKSLASH); + output_character(char32_t(std::uint8_t('u'))); + output_character(char32_t(std::uint8_t('2'))); + output_character(char32_t(std::uint8_t('0'))); + output_character(char32_t(std::uint8_t('2'))); + output_character(char32_t(std::uint8_t('9'))); + break; + default: + if (C0_CONTROL_LAST >= ch) + { + ++m_c0_control_escaped; + if (!m_escape) + output_character(BACKSLASH); + output_character(char32_t(std::uint8_t('u'))); + output_character(char32_t(std::uint8_t('0'))); + output_character(char32_t(std::uint8_t('0'))); + output_character(char32_t(std::uint8_t('0') + (ch / 0x10U))); + output_character(char32_t(std::uint8_t('0') + (ch % 0x10U))); + } + else + { + output_character(ch); + if (!m_escape && (DOUBLE_QUOTE == ch)) + m_parse_state = parse_state::DEFAULT; + } + } + m_escape = (BACKSLASH == ch) && !m_escape; +} + + + +/*************************************************************************** XML DATA CLEANER CLASS ***************************************************************************/ @@ -1785,6 +2195,13 @@ bool is_lua_source_extension(char const *ext) } +bool is_json_extension(char const *ext) +{ + return + !core_stricmp(ext, ".json"); +} + + bool is_xml_extension(char const *ext) { return @@ -1806,7 +2223,7 @@ int main(int argc, char *argv[]) { bool keep_backup(false); bool dry_run(false); -#if defined(WIN32) +#if defined(_WIN32) cleaner_base::newline newline_mode(cleaner_base::newline::DOS); #else cleaner_base::newline newline_mode(cleaner_base::newline::UNIX); @@ -1848,13 +2265,13 @@ int main(int argc, char *argv[]) { // open the file util::core_file::ptr infile; - osd_file::error const err(util::core_file::open(argv[i], OPEN_FLAG_READ, infile)); - if (osd_file::error::NONE != err) + std::error_condition const err(util::core_file::open(argv[i], OPEN_FLAG_READ, infile)); + if (err) { if (affected) std::cerr << std::endl; affected = true; - util::stream_format(std::cerr, "Can't open %1$s\n", argv[i]); + util::stream_format(std::cerr, "Can't open %1$s (%2$s)\n", argv[i], err.message()); ++failures; continue; } @@ -1865,12 +2282,15 @@ int main(int argc, char *argv[]) char const *const ext(std::strrchr(argv[i], '.')); bool const is_c_file(ext && is_c_source_extension(ext)); bool const is_lua_file(ext && is_lua_source_extension(ext)); + bool const is_json_file(ext && is_json_extension(ext)); bool const is_xml_file(ext && is_xml_extension(ext)); std::unique_ptr<cleaner_base> cleaner; if (is_c_file) cleaner = std::make_unique<cpp_cleaner>(std::back_inserter(output), newline_mode, 4U); else if (is_lua_file) cleaner = std::make_unique<lua_cleaner>(std::back_inserter(output), newline_mode, 4U); + else if (is_json_file) + cleaner = std::make_unique<json_cleaner>(std::back_inserter(output), newline_mode, 4U); else if (is_xml_file) cleaner = std::make_unique<xml_cleaner>(std::back_inserter(output), newline_mode, 4U); else @@ -1878,12 +2298,29 @@ int main(int argc, char *argv[]) // read/process in chunks output.clear(); - std::uint64_t remaining(infile->size()); - std::uint32_t block; - while (remaining && (0U != (block = infile->read(original, (std::min)(std::uint64_t(sizeof(original)), remaining))))) + std::uint64_t remaining; + if (infile->length(remaining)) + { + util::stream_format(std::cerr, "Can't get length of %1$s\n", argv[i]); + ++failures; + continue; + } + 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/testkeys.cpp b/src/tools/testkeys.cpp index 9ee08808c19..3c00dd79854 100644 --- a/src/tools/testkeys.cpp +++ b/src/tools/testkeys.cpp @@ -2,8 +2,8 @@ // // testkeys.cpp - A small utility to analyze SDL keycodes // -// Copyright (c) 1996-2019, Nicola Salmoria and the MAME Team. -// Visit http://mamedev.org for licensing and usage restrictions. +// Copyright (c) 1996-2022, Nicola Salmoria and the MAME Team. +// Visit https://mamedev.org for licensing and usage restrictions. // // SDLMAME by Olivier Galibert and R. Belmont // testkeys by couriersud diff --git a/src/tools/unidasm.cpp b/src/tools/unidasm.cpp index cd164db7776..be64dc9cb72 100644 --- a/src/tools/unidasm.cpp +++ b/src/tools/unidasm.cpp @@ -2,13 +2,12 @@ // copyright-holders:Aaron Giles /*************************************************************************** - mamedasm.c - - Generic MAME disassembler. + Universal disassembler. ****************************************************************************/ // the disassemblers assume they're in MAME and emu.h is a PCH, so we minimally pander to them +#include "coretmpl.h" #include "disasmintf.h" using offs_t = osd::u32; @@ -16,7 +15,6 @@ using util::BIT; #include "cpu/8x300/8x300dasm.h" #include "cpu/adsp2100/2100dasm.h" -#include "cpu/alph8201/8201dasm.h" #include "cpu/alpha/alphad.h" #include "cpu/alto2/alto2dsm.h" #include "cpu/am29000/am29dasm.h" @@ -29,63 +27,89 @@ 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" #include "cpu/cop400/cop420ds.h" #include "cpu/cop400/cop424ds.h" #include "cpu/cop400/cop444ds.h" +#include "cpu/cops1/cops1d.h" #include "cpu/cosmac/cosdasm.h" #include "cpu/cp1610/1610dasm.h" #include "cpu/cr16b/cr16bdasm.h" +#include "cpu/cr16c/cr16cdasm.h" #include "cpu/cubeqcpu/cubedasm.h" +#include "cpu/ddp516/ddp516d.h" #include "cpu/dsp16/dsp16dis.h" #include "cpu/dsp32/dsp32dis.h" +#include "cpu/dsp56000/dsp56000d.h" #include "cpu/dsp56156/dsp56dsm.h" #include "cpu/e0c6200/e0c6200d.h" #include "cpu/e132xs/32xsdasm.h" #include "cpu/es5510/es5510d.h" #include "cpu/esrip/esripdsm.h" -#include "cpu/f2mc16/f2mc16dasm.h" +#include "cpu/evolution/evod.h" +#include "cpu/f2mc16/f2mc16d.h" #include "cpu/f8/f8dasm.h" +#include "cpu/fr/frdasm.h" #include "cpu/g65816/g65816ds.h" +#include "cpu/gigatron/gigatrondasm.h" #include "cpu/h6280/6280dasm.h" +#include "cpu/h8/gt913d.h" #include "cpu/h8/h8d.h" #include "cpu/h8/h8hd.h" #include "cpu/h8/h8s2000d.h" #include "cpu/h8/h8s2600d.h" +#include "cpu/h16/h16dasm.h" +#include "cpu/h8500/h8500dasm.h" #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" +#include "cpu/ht1130/ht1130d.h" #include "cpu/i386/i386dasm.h" #include "cpu/i8008/8008dasm.h" #include "cpu/i8085/8085dasm.h" #include "cpu/i8089/i8089_dasm.h" #include "cpu/i860/i860dis.h" #include "cpu/i960/i960dis.h" +#include "cpu/ibm1800/ibm1800d.h" #include "cpu/ie15/ie15dasm.h" +#include "cpu/interdata16/dasm16.h" #include "cpu/jaguar/jagdasm.h" +#include "cpu/ks0164/ks0164d.h" +#include "cpu/lc57/lc57d.h" +#include "cpu/lc58/lc58d.h" #include "cpu/lc8670/lc8670dsm.h" #include "cpu/lh5801/5801dasm.h" #include "cpu/lr35902/lr35902d.h" +#include "cpu/m16c/m16cdasm.h" +#include "cpu/m32c/m32cdasm.h" #include "cpu/m37710/m7700ds.h" #include "cpu/m6502/m4510d.h" #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" #include "cpu/m68000/m68kdasm.h" #include "cpu/m6805/6805dasm.h" #include "cpu/m6809/6x09dasm.h" +#include "cpu/m68hc16/cpu16dasm.h" +#include "cpu/m88000/m88000d.h" #include "cpu/mb86233/mb86233d.h" #include "cpu/mb86235/mb86235d.h" #include "cpu/mb88xx/mb88dasm.h" @@ -93,29 +117,48 @@ using util::BIT; #include "cpu/mcs40/mcs40dasm.h" #include "cpu/mcs48/mcs48dsm.h" #include "cpu/mcs51/mcs51dasm.h" -#include "cpu/mcs51/axc51-core_dasm.h" +#include "cpu/axc51/axc51dasm.h" #include "cpu/mcs96/i8x9xd.h" #include "cpu/mcs96/i8xc196d.h" #include "cpu/melps4/melps4d.h" #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/ns32000/ns32000dasm.h" +#include "cpu/nios2/nios2dasm.h" +#include "cpu/nova/novadasm.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/pdp1/tx0dasm.h" #include "cpu/pdp8/pdp8dasm.h" +#include "cpu/pic16/pic16d.h" +#include "cpu/pic1670/pic1670d.h" #include "cpu/pic16c5x/16c5xdsm.h" #include "cpu/pic16c62x/16c62xdsm.h" +#include "cpu/pic17/pic17d.h" #include "cpu/powerpc/ppc_dasm.h" #include "cpu/pps4/pps4dasm.h" +#include "cpu/pps41/pps41d.h" #include "cpu/psx/psxdasm.h" #include "cpu/rii/riidasm.h" +#include "cpu/romp/rompdasm.h" #include "cpu/rsp/rsp_dasm.h" +#include "cpu/rw5000/rw5000d.h" +#include "cpu/rx01/rx01dasm.h" #include "cpu/s2650/2650dasm.h" #include "cpu/saturn/saturnds.h" #include "cpu/sc61860/scdasm.h" @@ -125,6 +168,7 @@ using util::BIT; #include "cpu/se3208/se3208dis.h" #include "cpu/sh/sh_dasm.h" #include "cpu/sharc/sharcdsm.h" +#include "cpu/sigma2/sigma2d.h" #include "cpu/sm510/sm510d.h" #include "cpu/sm8500/sm8500d.h" #include "cpu/sparc/sparcdasm.h" @@ -132,6 +176,7 @@ using util::BIT; #include "cpu/ssem/ssemdasm.h" #include "cpu/ssp1601/ssp1601d.h" #include "cpu/st62xx/st62xx_dasm.h" +#include "cpu/st9/st9dasm.h" #include "cpu/superfx/sfx_dasm.h" #include "cpu/t11/t11dasm.h" #include "cpu/tlcs870/tlcs870d.h" @@ -149,27 +194,61 @@ using util::BIT; #include "cpu/tms7000/7000dasm.h" #include "cpu/tms9900/9900dasm.h" #include "cpu/tms9900/tms99com.h" +#include "cpu/tx0/tx0dasm.h" #include "cpu/ucom4/ucom4d.h" #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" +#include "cpu/upd78k/upd78k2d.h" +#include "cpu/upd78k/upd78k3d.h" +#include "cpu/upd78k/upd78k4d.h" #include "cpu/v60/v60d.h" +#include "cpu/v620/v620dasm.h" #include "cpu/v810/v810dasm.h" +#include "cpu/v850/v850dasm.h" +#include "cpu/vax/vaxdasm.h" +#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" -#include "corefile.h" #include "corestr.h" #include "eminline.h" +#include "endianness.h" +#include "ioprocs.h" +#include "osdfile.h" +#include "strformat.h" #include <algorithm> +#include <cctype> +#include <cstdio> +#include <cstdlib> #include <cstring> +#include <functional> #include <iostream> +#include <memory> #include <stdexcept> +#include <string> +#include <utility> +#include <vector> + +#ifdef _WIN32 +#include <fcntl.h> +#include <io.h> +#include <stdio.h> +#endif -#include <ctype.h> using u8 = util::u8; using u16 = util::u16; @@ -194,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; @@ -270,22 +348,29 @@ 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; +// Configuration missing +struct nec_unidasm_t : nec_disassembler::config +{ + int mode; + nec_unidasm_t() { mode = 1; } + virtual ~nec_unidasm_t() override = default; + virtual int get_mode() const override { return mode; } +} nec_unidasm; -enum endianness { le, be }; +static constexpr auto le = util::endianness::little; +static constexpr auto be = util::endianness::big; struct dasm_table_entry { const char * name; - endianness endian; + util::endianness endian; int8_t pcshift; std::function<util::disasm_interface *()> alloc; }; @@ -300,10 +385,10 @@ struct options uint8_t lower; uint8_t upper; uint8_t flipped; - int mode; const dasm_table_entry *dasm; uint32_t skip; uint32_t count; + bool octal; }; static const dasm_table_entry dasm_table[] = @@ -314,15 +399,15 @@ static const dasm_table_entry dasm_table[] = { "alpha_nt", le, 0, []() -> util::disasm_interface * { return new alpha_disassembler(alpha_disassembler::TYPE_NT); } }, { "alpha_unix", le, 0, []() -> util::disasm_interface * { return new alpha_disassembler(alpha_disassembler::TYPE_UNIX); } }, { "alpha_vms", le, 0, []() -> util::disasm_interface * { return new alpha_disassembler(alpha_disassembler::TYPE_VMS); } }, - { "alpha8201", le, 0, []() -> util::disasm_interface * { return new alpha8201_disassembler; } }, { "alto2", be, -2, []() -> util::disasm_interface * { return new alto2_disassembler; } }, + { "a5000", le, 0, []() -> util::disasm_interface * { return new a5000_disassembler; } }, + { "a5500", le, 0, []() -> util::disasm_interface * { return new a5500_disassembler; } }, { "am29000", be, 0, []() -> util::disasm_interface * { return new am29000_disassembler; } }, { "amis2000", le, 0, []() -> util::disasm_interface * { return new amis2000_disassembler; } }, { "apexc", be, 0, []() -> util::disasm_interface * { return new apexc_disassembler; } }, { "arc", be, 0, []() -> util::disasm_interface * { return new arc_disassembler; } }, { "arcompact", le, 0, []() -> util::disasm_interface * { return new arcompact_disassembler; } }, { "arm", le, 0, []() -> util::disasm_interface * { return new arm_disassembler; } }, - { "arm_be", be, 0, []() -> util::disasm_interface * { return new arm_disassembler; } }, { "arm7", le, 0, []() -> util::disasm_interface * { arm7_unidasm.t_flag = false; return new arm7_disassembler(&arm7_unidasm); } }, { "arm7_be", be, 0, []() -> util::disasm_interface * { arm7_unidasm.t_flag = false; return new arm7_disassembler(&arm7_unidasm); } }, { "arm7thumb", le, 0, []() -> util::disasm_interface * { arm7_unidasm.t_flag = true; return new arm7_disassembler(&arm7_unidasm); } }, @@ -331,8 +416,16 @@ static const dasm_table_entry dasm_table[] = { "avr8", le, 0, []() -> util::disasm_interface * { return new avr8_disassembler; } }, { "axc51core", le, 0, []() -> util::disasm_interface * { return new axc51core_disassembler; } }, { "axc208", le, 0, []() -> util::disasm_interface * { return new ax208_disassembler; } }, + { "b5000", le, 0, []() -> util::disasm_interface * { return new b5000_disassembler; } }, + { "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); } }, { "cdp1805", le, 0, []() -> util::disasm_interface * { return new cosmac_disassembler(cosmac_disassembler::TYPE_1805); } }, @@ -343,41 +436,59 @@ static const dasm_table_entry dasm_table[] = { "cop444", le, 0, []() -> util::disasm_interface * { return new cop444_disassembler; } }, { "cop424", le, 0, []() -> util::disasm_interface * { return new cop424_disassembler; } }, { "cp1610", be, -1, []() -> util::disasm_interface * { return new cp1610_disassembler; } }, + { "cpu16", be, 0, []() -> util::disasm_interface * { return new cpu16_disassembler; } }, { "cr16a", le, 0, []() -> util::disasm_interface * { return new cr16a_disassembler; } }, { "cr16b", le, 0, []() -> util::disasm_interface * { return new cr16b_disassembler; } }, + { "cr16c", le, 0, []() -> util::disasm_interface * { return new cr16c_disassembler; } }, { "cquestlin", be, -3, []() -> util::disasm_interface * { return new cquestlin_disassembler; } }, { "cquestrot", be, -3, []() -> util::disasm_interface * { return new cquestrot_disassembler; } }, { "cquestsnd", be, -3, []() -> util::disasm_interface * { return new cquestsnd_disassembler; } }, + { "cyber18", be, -1, []() -> util::disasm_interface * { return new cyber18_disassembler; } }, + { "ddp516", be, -1, []() -> util::disasm_interface * { return new ddp516_disassembler; } }, { "dp8344", le, -1, []() -> util::disasm_interface * { return new dp8344_disassembler; } }, { "ds5002fp", le, 0, []() -> util::disasm_interface * { return new ds5002fp_disassembler; } }, + { "ds80c320", le, 0, []() -> util::disasm_interface * { return new ds80c320_disassembler; } }, { "dsp16", le, -1, []() -> util::disasm_interface * { return new dsp16_disassembler; } }, { "dsp32c", le, 0, []() -> util::disasm_interface * { return new dsp32c_disassembler; } }, + { "dsp56000", be, -2, []() -> util::disasm_interface * { return new dsp56000_disassembler; } }, { "dsp56156", le, -1, []() -> util::disasm_interface * { return new dsp56156_disassembler; } }, { "e0c6200", be, -1, []() -> util::disasm_interface * { return new e0c6200_disassembler; } }, { "epg3231", le, -1, []() -> util::disasm_interface * { return new epg3231_disassembler; } }, // { "es5510", be, 0, []() -> util::disasm_interface * { return new es5510_disassembler; } }, // Currently does nothing { "esrip", be, 0, []() -> util::disasm_interface * { return new esrip_disassembler; } }, + { "evo", le, -1, []() -> util::disasm_interface * { return new evolution_disassembler; } }, { "f2mc16", le, 0, []() -> util::disasm_interface * { return new f2mc16_disassembler; } }, { "f8", be, 0, []() -> util::disasm_interface * { return new f8_disassembler; } }, + { "fr", be, 0, []() -> util::disasm_interface * { return new fr_disassembler; } }, + { "fscpu32", be, 0, []() -> util::disasm_interface * { return new m68k_disassembler(m68k_disassembler::TYPE_CPU32); } }, { "g65816", le, 0, []() -> util::disasm_interface * { return new g65816_disassembler(&g65816_unidasm); } }, + { "gigatron", be, -1, []() -> util::disasm_interface * { return new gigatron_disassembler; } }, + { "gt913", be, 0, []() -> util::disasm_interface * { return new gt913_disassembler; } }, { "h6280", le, 0, []() -> util::disasm_interface * { return new h6280_disassembler; } }, { "h8", be, 0, []() -> util::disasm_interface * { return new h8_disassembler; } }, { "h8h", be, 0, []() -> util::disasm_interface * { return new h8h_disassembler; } }, { "h8s2000", be, 0, []() -> util::disasm_interface * { return new h8s2000_disassembler; } }, { "h8s2600", be, 0, []() -> util::disasm_interface * { return new h8s2600_disassembler; } }, + { "h8500", be, 0, []() -> util::disasm_interface * { return new h8500_disassembler; } }, + { "h16", be, 0, []() -> util::disasm_interface * { return new h16_disassembler; } }, { "hc11", be, 0, []() -> util::disasm_interface * { return new hc11_disassembler; } }, { "hcd62121", le, 0, []() -> util::disasm_interface * { return new hcd62121_disassembler; } }, + { "hd6120", be, -1, []() -> util::disasm_interface * { return new hd6120_disassembler; } }, { "hd61700", le, -1, []() -> util::disasm_interface * { return new hd61700_disassembler; } }, { "hd6301", be, 0, []() -> util::disasm_interface * { return new m680x_disassembler(6301); } }, { "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; } }, { "hp_5061_3011", be, -1, []() -> util::disasm_interface * { return new hp_5061_3011_disassembler; } }, { "hp_09825_67907", be, -1, []() -> util::disasm_interface * { return new hp_09825_67907_disassembler; } }, { "hpc16083", le, 0, []() -> util::disasm_interface * { return new hpc16083_disassembler; } }, { "hpc16164", le, 0, []() -> util::disasm_interface * { return new hpc16164_disassembler; } }, { "hyperstone", be, 0, []() -> util::disasm_interface * { return new hyperstone_disassembler(&hyperstone_unidasm); } }, + { "ht1130", le, 0, []() -> util::disasm_interface * { return new ht1130_disassembler; } }, { "i4004", le, 0, []() -> util::disasm_interface * { return new i4004_disassembler; } }, { "i4040", le, 0, []() -> util::disasm_interface * { return new i4040_disassembler; } }, { "i8008", le, 0, []() -> util::disasm_interface * { return new i8008_disassembler; } }, @@ -393,21 +504,29 @@ static const dasm_table_entry dasm_table[] = { "i8xc51fx", le, 0, []() -> util::disasm_interface * { return new i8xc51fx_disassembler; } }, { "i8xc51gb", le, 0, []() -> util::disasm_interface * { return new i8xc51gb_disassembler; } }, { "i960", le, 0, []() -> util::disasm_interface * { return new i960_disassembler; } }, + { "ibm1130", be, -1, []() -> util::disasm_interface * { return new ibm1130_disassembler; } }, + { "ibm1800", be, -1, []() -> util::disasm_interface * { return new ibm1800_disassembler; } }, { "ie15", le, 0, []() -> util::disasm_interface * { return new ie15_disassembler; } }, + { "interdata16", be, 0, []() -> util::disasm_interface * { return new interdata16_disassembler; } }, { "jaguardsp", be, 0, []() -> util::disasm_interface * { return new jaguar_disassembler(jaguar_disassembler::variant::DSP); } }, { "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; } }, { "lh5801", le, 0, []() -> util::disasm_interface * { return new lh5801_disassembler; } }, { "lr35902", le, 0, []() -> util::disasm_interface * { return new lr35902_disassembler; } }, { "m146805", be, 0, []() -> util::disasm_interface * { return new m146805_disassembler; } }, + { "m16c", le, 0, []() -> util::disasm_interface * { return new m16c_disassembler; } }, + { "m32c", le, 0, []() -> util::disasm_interface * { return new m32c_disassembler; } }, { "m37710", le, 0, []() -> util::disasm_interface * { return new m7700_disassembler(&m7700_unidasm); } }, { "m4510", le, 0, []() -> util::disasm_interface * { return new m4510_disassembler; } }, { "m58846", le, -1, []() -> util::disasm_interface * { return new melps4_disassembler; } }, { "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); } }, @@ -422,38 +541,75 @@ static const dasm_table_entry dasm_table[] = { "m6805", be, 0, []() -> util::disasm_interface * { return new m6805_disassembler; } }, { "m6808", be, 0, []() -> util::disasm_interface * { return new m680x_disassembler(6808); } }, { "m6809", be, 0, []() -> util::disasm_interface * { return new m6809_disassembler; } }, - { "m68340", be, 0, []() -> util::disasm_interface * { return new m68k_disassembler(m68k_disassembler::TYPE_68340); } }, { "m68hc05", be, 0, []() -> util::disasm_interface * { return new m68hc05_disassembler; } }, { "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); } }, { "minx", le, 0, []() -> util::disasm_interface * { return new minx_disassembler; } }, { "mips1be", be, 0, []() -> util::disasm_interface * { return new mips1_disassembler; } }, { "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; } }, + { "mn1860", be, 0, []() -> util::disasm_interface * { return new mn1860_disassembler; } }, + { "mn1870", be, 0, []() -> util::disasm_interface * { return new mn1870_disassembler; } }, + { "mn1880", be, 0, []() -> util::disasm_interface * { return new mn1880_disassembler; } }, + { "msm65x2", le, 0, []() -> util::disasm_interface * { return new msm65x2_disassembler; } }, { "nanoprocessor", le, 0, []() -> util::disasm_interface * { return new hp_nanoprocessor_disassembler; } }, - { "nec", le, 0, []() -> util::disasm_interface * { return new nec_disassembler; } }, + { "nec", le, 0, []() -> util::disasm_interface * { return new nec_disassembler(&nec_unidasm); } }, + { "nios2", le, 0, []() -> util::disasm_interface * { return new nios2_disassembler; } }, + { "nova", be, -1, []() -> util::disasm_interface * { return new nova_disassembler; } }, { "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, 0, []() -> util::disasm_interface * { return new pdp1_disassembler; } }, - { "pdp8", be, 0, []() -> util::disasm_interface * { return new pdp8_disassembler; } }, + { "pdp1", be, -2, []() -> util::disasm_interface * { return new pdp1_disassembler; } }, + { "pdp8", be, -1, []() -> util::disasm_interface * { return new pdp8_disassembler; } }, + { "pic16", le, -1, []() -> util::disasm_interface * { return new pic16_disassembler; } }, { "pic16c5x", le, -1, []() -> util::disasm_interface * { return new pic16c5x_disassembler; } }, + { "pic1670", le, -1, []() -> util::disasm_interface * { return new pic1670_disassembler; } }, { "pic16c62x", le, -1, []() -> util::disasm_interface * { return new pic16c62x_disassembler; } }, + { "pic17", le, -1, []() -> util::disasm_interface * { return new pic17_disassembler; } }, + { "power", be, 0, []() -> util::disasm_interface * { return new power_disassembler; } }, { "powerpc", be, 0, []() -> util::disasm_interface * { return new powerpc_disassembler; } }, { "pps4", le, 0, []() -> util::disasm_interface * { return new pps4_disassembler; } }, + { "prime16s", be, -1, []() -> util::disasm_interface * { return new prime16s_disassembler; } }, + { "prime32r", be, -1, []() -> util::disasm_interface * { return new prime32r_disassembler; } }, + { "prime32s", be, -1, []() -> util::disasm_interface * { return new prime32s_disassembler; } }, + { "prime64r", be, -1, []() -> util::disasm_interface * { return new prime64r_disassembler; } }, + { "prime64v", be, -1, []() -> util::disasm_interface * { return new prime64v_disassembler; } }, { "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; } }, - { "s2650", le, 0, []() -> util::disasm_interface * { return new s2650_disassembler(&s2650_unidasm); } }, + { "rupi44", le, 0, []() -> util::disasm_interface * { return new rupi44_disassembler; } }, + { "rx01", le, 0, []() -> util::disasm_interface * { return new rx01_disassembler; } }, + { "s2650", be, 0, []() -> util::disasm_interface * { return new s2650_disassembler(&s2650_unidasm); } }, + { "sab80515", le, 0, []() -> util::disasm_interface * { return new sab80515_disassembler; } }, + { "sab80c515", le, 0, []() -> util::disasm_interface * { return new sab80c515_disassembler; } }, { "saturn", le, 0, []() -> util::disasm_interface * { return new saturn_disassembler(&saturn_unidasm); } }, { "sc61860", le, 0, []() -> util::disasm_interface * { return new sc61860_disassembler; } }, - { "scmp", le, 0, []() -> util::disasm_interface * { return new scmp_disassembler; } }, + { "scmp", be, 0, []() -> util::disasm_interface * { return new scmp_disassembler; } }, { "score7", le, 0, []() -> util::disasm_interface * { return new score7_disassembler; } }, { "scudsp", be, -2, []() -> util::disasm_interface * { return new scudsp_disassembler; } }, { "se3208", le, 0, []() -> util::disasm_interface * { return new se3208_disassembler; } }, @@ -461,6 +617,7 @@ static const dasm_table_entry dasm_table[] = { "sh4", le, 0, []() -> util::disasm_interface * { return new sh_disassembler(true); } }, { "sh4be", be, 0, []() -> util::disasm_interface * { return new sh_disassembler(true); } }, { "sharc", le, -3, []() -> util::disasm_interface * { return new sharc_disassembler; } }, + { "sigma2", be, -1, []() -> util::disasm_interface * { return new sigma2_disassembler; } }, { "sm500", le, 0, []() -> util::disasm_interface * { return new sm500_disassembler; } }, { "sm510", le, 0, []() -> util::disasm_interface * { return new sm510_disassembler; } }, { "sm511", le, 0, []() -> util::disasm_interface * { return new sm511_disassembler; } }, @@ -468,26 +625,35 @@ static const dasm_table_entry dasm_table[] = { "sm590", le, 0, []() -> util::disasm_interface * { return new sm590_disassembler; } }, { "sm5a", le, 0, []() -> util::disasm_interface * { return new sm5a_disassembler; } }, { "sm8500", le, 0, []() -> util::disasm_interface * { return new sm8500_disassembler; } }, - { "sparcv7", be, 0, []() -> util::disasm_interface * { return new sparc_disassembler(nullptr, 7); } }, - { "sparcv8", be, 0, []() -> util::disasm_interface * { return new sparc_disassembler(nullptr, 8); } }, - { "sparcv9", be, 0, []() -> util::disasm_interface * { return new sparc_disassembler(nullptr, 9); } }, - { "sparcv9vis1", be, 0, []() -> util::disasm_interface * { return new sparc_disassembler(nullptr, 9, sparc_disassembler::vis_1); } }, - { "sparcv9vis2", be, 0, []() -> util::disasm_interface * { return new sparc_disassembler(nullptr, 9, sparc_disassembler::vis_2); } }, - { "sparcv9vis2p", be, 0, []() -> util::disasm_interface * { return new sparc_disassembler(nullptr, 9, sparc_disassembler::vis_2p); } }, - { "sparcv9vis3", be, 0, []() -> util::disasm_interface * { return new sparc_disassembler(nullptr, 9, sparc_disassembler::vis_3); } }, - { "sparcv9vis3b", be, 0, []() -> util::disasm_interface * { return new sparc_disassembler(nullptr, 9, sparc_disassembler::vis_3b); } }, + { "smc1102", le, 0, []() -> util::disasm_interface * { return new smc1102_disassembler; } }, + { "sparclite", be, 0, []() -> util::disasm_interface * { return new sparc_disassembler(nullptr, sparc_disassembler::sparclite); } }, + { "sparcv7", be, 0, []() -> util::disasm_interface * { return new sparc_disassembler(nullptr, sparc_disassembler::v7); } }, + { "sparcv8", be, 0, []() -> util::disasm_interface * { return new sparc_disassembler(nullptr, sparc_disassembler::v8); } }, + { "sparcv9", be, 0, []() -> util::disasm_interface * { return new sparc_disassembler(nullptr, sparc_disassembler::v9); } }, + { "sparcv9vis1", be, 0, []() -> util::disasm_interface * { return new sparc_disassembler(nullptr, sparc_disassembler::v9, sparc_disassembler::vis_1); } }, + { "sparcv9vis2", be, 0, []() -> util::disasm_interface * { return new sparc_disassembler(nullptr, sparc_disassembler::v9, sparc_disassembler::vis_2); } }, + { "sparcv9vis2p", be, 0, []() -> util::disasm_interface * { return new sparc_disassembler(nullptr, sparc_disassembler::v9, sparc_disassembler::vis_2p); } }, + { "sparcv9vis3", be, 0, []() -> util::disasm_interface * { return new sparc_disassembler(nullptr, sparc_disassembler::v9, sparc_disassembler::vis_3); } }, + { "sparcv9vis3b", be, 0, []() -> util::disasm_interface * { return new sparc_disassembler(nullptr, sparc_disassembler::v9, sparc_disassembler::vis_3b); } }, { "spc700", le, 0, []() -> util::disasm_interface * { return new spc700_disassembler; } }, { "ssem", le, 0, []() -> util::disasm_interface * { return new ssem_disassembler; } }, { "ssp1601", be, -1, []() -> util::disasm_interface * { return new ssp1601_disassembler; } }, { "st62xx", le, 0, []() -> util::disasm_interface * { return new st62xx_disassembler; } }, + { "st9", be, 0, []() -> util::disasm_interface * { return new st9_disassembler; } }, + { "st9p", be, 0, []() -> util::disasm_interface * { return new st9p_disassembler; } }, { "superfx", le, 0, []() -> util::disasm_interface * { return new superfx_disassembler(&superfx_unidasm); } }, { "t11", le, 0, []() -> util::disasm_interface * { return new t11_disassembler; } }, { "tlcs870", le, 0, []() -> util::disasm_interface * { return new tlcs870_disassembler; } }, - { "tlcs90", le, 0, []() -> util::disasm_interface * { return new tlcs90_disassembler; } }, { "tlcs900", le, 0, []() -> util::disasm_interface * { return new tlcs900_disassembler; } }, + { "tmp90c051", le, 0, []() -> util::disasm_interface * { return new tmp90c051_disassembler; } }, + { "tmp90840", le, 0, []() -> util::disasm_interface * { return new tmp90840_disassembler; } }, + { "tmp90844", le, 0, []() -> util::disasm_interface * { return new tmp90844_disassembler; } }, { "tms0980", be, 0, []() -> util::disasm_interface * { return new tms0980_disassembler; } }, { "tms1000", le, 0, []() -> util::disasm_interface * { return new tms1000_disassembler; } }, { "tms1100", le, 0, []() -> util::disasm_interface * { return new tms1100_disassembler; } }, + { "tms1400", le, 0, []() -> util::disasm_interface * { return new tms1400_disassembler; } }, + { "tms2100", le, 0, []() -> util::disasm_interface * { return new tms2100_disassembler; } }, + { "tms2400", le, 0, []() -> util::disasm_interface * { return new tms2400_disassembler; } }, { "tms32010", be, -1, []() -> util::disasm_interface * { return new tms32010_disassembler; } }, { "tms32025", be, -1, []() -> util::disasm_interface * { return new tms32025_disassembler; } }, { "tms32031", le, -2, []() -> util::disasm_interface * { return new tms32031_disassembler; } }, @@ -504,23 +670,76 @@ static const dasm_table_entry dasm_table[] = { "tp0320", be, 0, []() -> util::disasm_interface * { return new tp0320_disassembler; } }, { "tx0_64kw", be, -2, []() -> util::disasm_interface * { return new tx0_64kw_disassembler; } }, { "tx0_8kw", be, -2, []() -> util::disasm_interface * { return new tx0_8kw_disassembler; } }, + { "tx0_8kwo", be, -2, []() -> util::disasm_interface * { return new tx0_8kwo_disassembler; } }, { "ucom4", le, 0, []() -> util::disasm_interface * { return new ucom4_disassembler; } }, { "unsp10", be, -1, []() -> util::disasm_interface * { return new unsp_disassembler; } }, { "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; } }, { "upd7807", le, 0, []() -> util::disasm_interface * { return new upd7807_disassembler; } }, { "upd7810", le, 0, []() -> util::disasm_interface * { return new upd7810_disassembler; } }, - { "upd78c05", le, 0, []() -> util::disasm_interface * { return new upd78c05_disassembler; } }, + { "upd78014", le, 0, []() -> util::disasm_interface * { return new upd78014_disassembler; } }, + { "upd78024", le, 0, []() -> util::disasm_interface * { return new upd78024_disassembler; } }, + { "upd78044a", le, 0, []() -> util::disasm_interface * { return new upd78044a_disassembler; } }, + { "upd78054", le, 0, []() -> util::disasm_interface * { return new upd78054_disassembler; } }, + { "upd78064", le, 0, []() -> util::disasm_interface * { return new upd78064_disassembler; } }, + { "upd78078", le, 0, []() -> util::disasm_interface * { return new upd78078_disassembler; } }, + { "upd78083", le, 0, []() -> util::disasm_interface * { return new upd78083_disassembler; } }, + { "upd78138", le, 0, []() -> util::disasm_interface * { return new upd78138_disassembler; } }, + { "upd78148", le, 0, []() -> util::disasm_interface * { return new upd78148_disassembler; } }, + { "upd78214", le, 0, []() -> util::disasm_interface * { return new upd78214_disassembler; } }, + { "upd78218a", le, 0, []() -> util::disasm_interface * { return new upd78218a_disassembler; } }, + { "upd78224", le, 0, []() -> util::disasm_interface * { return new upd78224_disassembler; } }, + { "upd78234", le, 0, []() -> util::disasm_interface * { return new upd78234_disassembler; } }, + { "upd78244", le, 0, []() -> util::disasm_interface * { return new upd78244_disassembler; } }, + { "upd780024a", le, 0, []() -> util::disasm_interface * { return new upd780024a_disassembler; } }, + { "upd78312", le, 0, []() -> util::disasm_interface * { return new upd78312_disassembler; } }, + { "upd78322", le, 0, []() -> util::disasm_interface * { return new upd78322_disassembler; } }, + { "upd78328", le, 0, []() -> util::disasm_interface * { return new upd78328_disassembler; } }, + { "upd78334", le, 0, []() -> util::disasm_interface * { return new upd78334_disassembler; } }, + { "upd78352", le, 0, []() -> util::disasm_interface * { return new upd78352_disassembler; } }, + { "upd78356", le, 0, []() -> util::disasm_interface * { return new upd78356_disassembler; } }, + { "upd78366a", le, 0, []() -> util::disasm_interface * { return new upd78366a_disassembler; } }, + { "upd78372", le, 0, []() -> util::disasm_interface * { return new upd78372_disassembler; } }, + { "upd784026", le, 0, []() -> util::disasm_interface * { return new upd784026_disassembler; } }, + { "upd784038", le, 0, []() -> util::disasm_interface * { return new upd784038_disassembler; } }, + { "upd784046", le, 0, []() -> util::disasm_interface * { return new upd784046_disassembler; } }, + { "upd784054", le, 0, []() -> util::disasm_interface * { return new upd784054_disassembler; } }, + { "upd784216", le, 0, []() -> util::disasm_interface * { return new upd784216_disassembler; } }, + { "upd784218", le, 0, []() -> util::disasm_interface * { return new upd784218_disassembler; } }, + { "upd784225", le, 0, []() -> util::disasm_interface * { return new upd784225_disassembler; } }, + { "upd780065", le, 0, []() -> util::disasm_interface * { return new upd780065_disassembler; } }, + { "upd780988", le, 0, []() -> util::disasm_interface * { return new upd78083_disassembler; } }, + { "upd78k0kx1", le, 0, []() -> util::disasm_interface * { return new upd78k0kx1_disassembler; } }, + { "upd78k0kx2", le, 0, []() -> util::disasm_interface * { return new upd78k0kx2_disassembler; } }, { "upi41", le, 0, []() -> util::disasm_interface * { return new mcs48_disassembler(true, false); } }, { "v60", le, 0, []() -> util::disasm_interface * { return new v60_disassembler; } }, + { "v620", be, -1, []() -> util::disasm_interface * { return new v620_disassembler; } }, + { "v620f", be, -1, []() -> util::disasm_interface * { return new v620f_disassembler; } }, + { "v75", be, -1, []() -> util::disasm_interface * { return new v75_disassembler; } }, { "v810", le, 0, []() -> util::disasm_interface * { return new v810_disassembler; } }, + { "v850", le, 0, []() -> util::disasm_interface * { return new v850_disassembler; } }, + { "v850es", le, 0, []() -> util::disasm_interface * { return new v850es_disassembler; } }, + { "v850e2", le, 0, []() -> util::disasm_interface * { return new v850e2_disassembler; } }, + { "vax", le, 0, []() -> util::disasm_interface * { return new vax_disassembler; } }, + { "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; } }, + { "xerox530", be, -1, []() -> util::disasm_interface * { return new xerox530_disassembler; } }, + { "xtensa", le, 0, []() -> util::disasm_interface * { return new xtensa_disassembler; } }, { "z180", le, 0, []() -> util::disasm_interface * { return new z180_disassembler; } }, { "z8", be, 0, []() -> util::disasm_interface * { return new z8_disassembler; } }, { "z80", le, 0, []() -> util::disasm_interface * { return new z80_disassembler; } }, @@ -531,7 +750,7 @@ class unidasm_data_buffer : public util::disasm_interface::data_buffer { public: std::vector<u8> data; - offs_t base_pc; + offs_t base_pc = 0; u32 size; unidasm_data_buffer(util::disasm_interface *disasm, const dasm_table_entry *entry); @@ -584,18 +803,17 @@ unidasm_data_buffer::unidasm_data_buffer(util::disasm_interface *_disasm, const switch(entry->pcshift) { case -1: lr8 = [](offs_t pc) -> u8 { throw std::logic_error("debug_disasm_buffer::debug_data_buffer: r8 access on 16-bits granularity bus\n"); }; - lr16 = [this](offs_t pc) -> u16 { - const u16 *src = get_ptr<u16>(pc); - return src[0]; - }; - switch(entry->endian) { case le: + lr16 = [this](offs_t pc) -> u16 { + const u16 *src = get_ptr<u16>(pc); + return little_endianize_int16(src[0]); + }; lr32 = [this, page_mask](offs_t pc) -> u32 { offs_t lpc = disasm->pc_real_to_linear(pc); u32 r = 0; for(int j=0; j != 2; j++) { - r |= get<u16>(disasm->pc_linear_to_real(lpc)) << (j*16); + r |= little_endianize_int16(get<u16>(disasm->pc_linear_to_real(lpc))) << (j*16); lpc = (lpc & ~page_mask) | ((lpc + 1) & page_mask); } return r; @@ -604,7 +822,7 @@ unidasm_data_buffer::unidasm_data_buffer(util::disasm_interface *_disasm, const offs_t lpc = disasm->pc_real_to_linear(pc); u64 r = 0; for(int j=0; j != 4; j++) { - r |= u64(get<u16>(disasm->pc_linear_to_real(lpc))) << (j*16); + r |= u64(little_endianize_int16(get<u16>(disasm->pc_linear_to_real(lpc)))) << (j*16); lpc = (lpc & ~page_mask) | ((lpc + 1) & page_mask); } return r; @@ -612,11 +830,15 @@ unidasm_data_buffer::unidasm_data_buffer(util::disasm_interface *_disasm, const break; case be: + lr16 = [this](offs_t pc) -> u16 { + const u16 *src = get_ptr<u16>(pc); + return big_endianize_int16(src[0]); + }; lr32 = [this, page_mask](offs_t pc) -> u32 { offs_t lpc = disasm->pc_real_to_linear(pc); u32 r = 0; for(int j=0; j != 2; j++) { - r |= get<u16>(disasm->pc_linear_to_real(lpc)) << ((1-j)*16); + r |= big_endianize_int16(get<u16>(disasm->pc_linear_to_real(lpc))) << ((1-j)*16); lpc = (lpc & ~page_mask) | ((lpc + 1) & page_mask); } return r; @@ -625,7 +847,7 @@ unidasm_data_buffer::unidasm_data_buffer(util::disasm_interface *_disasm, const offs_t lpc = disasm->pc_real_to_linear(pc); u64 r = 0; for(int j=0; j != 4; j++) { - r |= u64(get<u16>(disasm->pc_linear_to_real(lpc))) << ((3-j)*16); + r |= u64(big_endianize_int16(get<u16>(disasm->pc_linear_to_real(lpc)))) << ((3-j)*16); lpc = (lpc & ~page_mask) | ((lpc + 1) & page_mask); } return r; @@ -778,46 +1000,52 @@ unidasm_data_buffer::unidasm_data_buffer(util::disasm_interface *_disasm, const case -1: lr8 = [](offs_t pc) -> u8 { abort(); }; - lr16 = [this](offs_t pc) -> u16 { - const u16 *p = get_ptr<u16>(pc); - return p ? - p[0] - : 0x0000; - }; switch(entry->endian) { case le: + lr16 = [this](offs_t pc) -> u16 { + const u16 *p = get_ptr<u16>(pc); + return p ? + little_endianize_int16(p[0]) + : 0x0000; + }; lr32 = [this](offs_t pc) -> u32 { const u16 *p = get_ptr<u16>(pc); return p ? - p[0] | - (p[1] << 16) + little_endianize_int16(p[0]) | + (little_endianize_int16(p[1]) << 16) : 0x00000000; }; lr64 = [this](offs_t pc) -> u64 { const u16 *p = get_ptr<u16>(pc); return p ? - p[0] | - (p[1] << 16) | - (u64(p[2]) << 32) | - (u64(p[3]) << 48) + little_endianize_int16(p[0]) | + (little_endianize_int16(p[1]) << 16) | + (u64(little_endianize_int16(p[2])) << 32) | + (u64(little_endianize_int16(p[3])) << 48) : 0x0000000000000000; }; break; case be: + lr16 = [this](offs_t pc) -> u16 { + const u16 *p = get_ptr<u16>(pc); + return p ? + big_endianize_int16(p[0]) + : 0x0000; + }; lr32 = [this](offs_t pc) -> u32 { const u16 *p = get_ptr<u16>(pc); return p ? - (p[0] << 16)| - p[1] + (big_endianize_int16(p[0]) << 16)| + big_endianize_int16(p[1]) : 0x00000000; }; lr64 = [this](offs_t pc) -> u64 { const u16 *p = get_ptr<u16>(pc); return p ? - (u64(p[0]) << 48) | - (u64(p[1]) << 32) | - (p[2] << 16) | - p[3] + (u64(big_endianize_int16(p[0])) << 48) | + (u64(big_endianize_int16(p[1])) << 32) | + (big_endianize_int16(p[2]) << 16) | + big_endianize_int16(p[3]) : 0x0000000000000000; }; break; @@ -827,28 +1055,34 @@ unidasm_data_buffer::unidasm_data_buffer(util::disasm_interface *_disasm, const case -2: lr8 = [](offs_t pc) -> u8 { abort(); }; lr16 = [](offs_t pc) -> u16 { abort(); }; - lr32 = [this](offs_t pc) -> u32 { - const u32 *p = get_ptr<u32>(pc); - return p ? - p[0] - : 0x00000000; - }; switch(entry->endian) { case le: + lr32 = [this](offs_t pc) -> u32 { + const u32 *p = get_ptr<u32>(pc); + return p ? + little_endianize_int32(p[0]) + : 0x00000000; + }; lr64 = [this](offs_t pc) -> u64 { const u32 *p = get_ptr<u32>(pc); return p ? - p[0] | - (u64(p[1]) << 32) + little_endianize_int32(p[0]) | + (u64(little_endianize_int32(p[1])) << 32) : 0x0000000000000000; }; break; case be: + lr32 = [this](offs_t pc) -> u32 { + const u32 *p = get_ptr<u32>(pc); + return p ? + big_endianize_int32(p[0]) + : 0x00000000; + }; lr64 = [this](offs_t pc) -> u64 { const u32 *p = get_ptr<u32>(pc); return p ? - (u64(p[0]) << 32) | - p[1] + (u64(big_endianize_int32(p[0])) << 32) | + big_endianize_int32(p[1]) : 0x0000000000000000; }; break; @@ -859,26 +1093,38 @@ unidasm_data_buffer::unidasm_data_buffer(util::disasm_interface *_disasm, const lr8 = [](offs_t pc) -> u8 { abort(); }; lr16 = [](offs_t pc) -> u16 { abort(); }; lr32 = [](offs_t pc) -> u32 { abort(); }; - lr64 = [this](offs_t pc) -> u64 { - const u64 *p = get_ptr<u64>(pc); - return p ? - p[0] - : 0x0000000000000000; + switch(entry->endian) { + case le: + lr64 = [this](offs_t pc) -> u64 { + const u64 *p = get_ptr<u64>(pc); + return p ? + little_endianize_int64(p[0]) + : 0x0000000000000000; + }; + break; + case be: + lr64 = [this](offs_t pc) -> u64 { + const u64 *p = get_ptr<u64>(pc); + return p ? + big_endianize_int64(p[0]) + : 0x0000000000000000; + }; + break; }; break; case 3: lr8 = [](offs_t pc) -> u8 { abort(); }; - lr16 = [this](offs_t pc) -> u16 { - if(pc < base_pc) - return 0x0000; - offs_t delta = (pc - base_pc) >> 3; - if(delta >= size) - return 0x0000; - return reinterpret_cast<const u16 *>(&data[delta])[0]; - }; switch(entry->endian) { case le: + lr16 = [this](offs_t pc) -> u16 { + if(pc < base_pc) + return 0x0000; + offs_t delta = (pc - base_pc) >> 3; + if(delta >= size) + return 0x0000; + return little_endianize_int16(reinterpret_cast<const u16 *>(&data[delta])[0]); + }; lr32 = [this](offs_t pc) -> u32 { if(pc < base_pc) return 0x00000000; @@ -886,10 +1132,18 @@ unidasm_data_buffer::unidasm_data_buffer(util::disasm_interface *_disasm, const if(delta >= size + 2) return 0x00000000; auto p = reinterpret_cast<const u16 *>(&data[delta]); - return p[0] | (u32(p[1]) << 16); + return little_endianize_int16(p[0]) | (u32(little_endianize_int16(p[1])) << 16); }; break; case be: + lr16 = [this](offs_t pc) -> u16 { + if(pc < base_pc) + return 0x0000; + offs_t delta = (pc - base_pc) >> 3; + if(delta >= size) + return 0x0000; + return big_endianize_int16(reinterpret_cast<const u16 *>(&data[delta])[0]); + }; lr32 = [this](offs_t pc) -> u32 { if(pc < base_pc) return 0x00000000; @@ -897,7 +1151,7 @@ unidasm_data_buffer::unidasm_data_buffer(util::disasm_interface *_disasm, const if(delta >= size + 2) return 0x00000000; auto p = reinterpret_cast<const u16 *>(&data[delta]); - return (u32(p[0]) << 16) | p[1]; + return (u32(big_endianize_int16(p[0])) << 16) | big_endianize_int16(p[1]); }; break; } @@ -915,11 +1169,28 @@ void unidasm_data_buffer::decrypt(const unidasm_data_buffer &buffer, bool opcode abort(); } +static int parse_number(const char *curarg, const char *default_format, u32 *value) +{ + int result; + if(curarg[0] == '0') { + if(tolower((uint8_t)curarg[1]) == 'x') + result = sscanf(&curarg[2], "%x", value); + else if(tolower((uint8_t)curarg[1]) == 'o') + result = sscanf(&curarg[2], "%o", value); + else + result = sscanf(&curarg[1], "%o", value); + } + else if(curarg[0] == '$') + result = sscanf(&curarg[1], "%x", value); + else + result = sscanf(&curarg[0], default_format, value); + return result; +} + static int parse_options(int argc, char *argv[], options *opts) { bool pending_base = false; bool pending_arch = false; - bool pending_mode = false; bool pending_skip = false; bool pending_count = false; @@ -930,8 +1201,8 @@ static int parse_options(int argc, char *argv[], options *opts) char *curarg = argv[arg]; // is it a switch? - if(curarg[0] == '-') { - if(pending_base || pending_arch || pending_mode || pending_skip || pending_count) + if(curarg[0] == '-' && curarg[1] != '\0') { + if(pending_base || pending_arch || pending_skip || pending_count) goto usage; if(tolower((uint8_t)curarg[1]) == 'a') @@ -942,8 +1213,6 @@ static int parse_options(int argc, char *argv[], options *opts) opts->flipped = true; else if(tolower((uint8_t)curarg[1]) == 'l') opts->lower = true; - else if(tolower((uint8_t)curarg[1]) == 'm') - pending_mode = true; else if(tolower((uint8_t)curarg[1]) == 's') pending_skip = true; else if(tolower((uint8_t)curarg[1]) == 'c') @@ -954,119 +1223,86 @@ static int parse_options(int argc, char *argv[], options *opts) opts->upper = true; else if(tolower((uint8_t)curarg[1]) == 'x') opts->xchbytes = true; + else if(tolower((uint8_t)curarg[1]) == 'o') + opts->octal = true; else goto usage; - } + } else if(pending_base) { // base PC - else if(pending_base) - { - int result; - if(curarg[0] == '0' && curarg[1] == 'x') - result = sscanf(&curarg[2], "%x", &opts->basepc); - else if(curarg[0] == '$') - result = sscanf(&curarg[1], "%x", &opts->basepc); - else - result = sscanf(&curarg[0], "%x", &opts->basepc); - if(result != 1) + if(parse_number(curarg, "%x", &opts->basepc) != 1) goto usage; pending_base = false; - } - // mode - else if(pending_mode) - { - if(sscanf(curarg, "%d", &opts->mode) != 1) + } else if(pending_arch) { + // architecture + auto const arch = std::find_if( + std::begin(dasm_table), + std::end(dasm_table), + [&curarg] (dasm_table_entry const &e) { return !core_stricmp(curarg, e.name); }); + if (std::end(dasm_table) == arch) goto usage; - pending_mode = false; - } - - // architecture - else if(pending_arch) { - int curarch; - for(curarch = 0; curarch < ARRAY_LENGTH(dasm_table); curarch++) - if(core_stricmp(curarg, dasm_table[curarch].name) == 0) - break; - if(curarch == ARRAY_LENGTH(dasm_table)) - goto usage; - opts->dasm = &dasm_table[curarch]; + opts->dasm = &*arch; pending_arch = false; - } - // skip bytes - else if(pending_skip) { - int result; - if(curarg[0] == '0' && curarg[1] == 'x') - result = sscanf(&curarg[2], "%x", &opts->skip); - else - result = sscanf(curarg, "%d", &opts->skip); - if(result != 1) + } else if(pending_skip) { + // skip bytes + if(parse_number(curarg, "%d", &opts->skip) != 1) goto usage; pending_skip = false; - } - // size - else if(pending_count) { - if(sscanf(curarg, "%d", &opts->count) != 1) + } else if(pending_count) { + // size + if(parse_number(curarg, "%d", &opts->count) != 1) goto usage; pending_count = false; - } - // filename - else if(opts->filename == nullptr) + } else if(opts->filename == nullptr) { + // filename opts->filename = curarg; - // fail - else + } else { + // fail goto usage; + } } // if we have a dangling option, error - if(pending_base || pending_arch || pending_mode || pending_skip || pending_count) + if(pending_base || pending_arch || pending_skip || pending_count) goto usage; // if no file or no architecture, fail if(opts->filename == nullptr || opts->dasm == nullptr) goto usage; + return 0; usage: printf("Usage: %s <filename> -arch <architecture> [-basepc <pc>] \n", argv[0]); - printf(" [-mode <n>] [-norawbytes] [-xchbytes] [-flipped] [-upper] [-lower]\n"); - printf(" [-skip <n>] [-count <n>]\n"); + printf(" [-norawbytes] [-xchbytes] [-flipped] [-upper] [-lower]\n"); + printf(" [-skip <n>] [-count <n>] [-octal]\n"); printf("\n"); printf("Supported architectures:"); const int colwidth = 1 + std::strlen(std::max_element(std::begin(dasm_table), std::end(dasm_table), [](const dasm_table_entry &a, const dasm_table_entry &b) { return std::strlen(a.name) < std::strlen(b.name); })->name); const int columns = std::max(1, 80 / colwidth); - const int numrows = (ARRAY_LENGTH(dasm_table) + columns - 1) / columns; - for(unsigned curarch = 0; curarch < numrows * columns; curarch++) - { + const int numrows = (std::size(dasm_table) + columns - 1) / columns; + for(unsigned curarch = 0; curarch < numrows * columns; curarch++) { const int row = curarch / columns; const int col = curarch % columns; const int index = col * numrows + row; if(col == 0) printf("\n "); - printf("%-*s", colwidth, (index < ARRAY_LENGTH(dasm_table)) ? dasm_table[index].name : ""); + printf("%-*s", colwidth, (index < std::size(dasm_table)) ? dasm_table[index].name : ""); } printf("\n"); return 1; }; -int main(int argc, char *argv[]) +int disasm_file(util::random_read &file, u64 length, options &opts) { - // Parse options first - options opts; - if(parse_options(argc, argv, &opts)) - return 1; - - // Load the file - void *data; - uint32_t length; - osd_file::error filerr = util::core_file::load(opts.filename, &data, length); - if(filerr != osd_file::error::NONE) - { - fprintf(stderr, "Error opening file '%s'\n", opts.filename); + if(opts.skip >= length) { + std::fprintf(stderr, "File '%s' is too short (only %llu bytes found)\n", opts.filename, (unsigned long long)length); return 1; } @@ -1079,18 +1315,19 @@ int main(int argc, char *argv[]) // Build the base buffer and fill it (with a margin) unidasm_data_buffer base_buffer(disasm.get(), opts.dasm); - u32 rounded_size = (((length - opts.skip) | (granularity - 1)) & ~(granularity - 1)); + u32 rounded_size = (((length - opts.skip) + (granularity - 1)) & ~(granularity - 1)); base_buffer.data.resize(rounded_size + 8, 0x00); base_buffer.size = length; base_buffer.base_pc = opts.basepc; + 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; + } if(opts.xchbytes) { - for(uint32_t offset = opts.skip; offset < length - 1; offset += 2) { - base_buffer.data[offset - opts.skip] = ((const u8 *)data)[offset + 1]; - base_buffer.data[offset - opts.skip + 1] = ((const u8 *)data)[offset]; - } + for(u64 offset = 0; offset < (length - opts.skip) - 1; offset += 2) + std::swap(base_buffer.data[offset], base_buffer.data[offset + 1]); } - else - memcpy(&base_buffer.data[0], (const u8 *)data + opts.skip, length - opts.skip); // Build the decryption buffers if needed unidasm_data_buffer opcodes_buffer(disasm.get(), opts.dasm), params_buffer(disasm.get(), opts.dasm); @@ -1104,18 +1341,12 @@ int main(int argc, char *argv[]) unidasm_data_buffer *popcodes = opcodes_buffer.data.empty() ? &base_buffer : &opcodes_buffer; unidasm_data_buffer *pparams = params_buffer.data.empty() ? popcodes : ¶ms_buffer; - // Compute the pc warparound + // Compute the pc wraparound offs_t pclength = opts.dasm->pcshift < 0 ? rounded_size >> -opts.dasm->pcshift : rounded_size << opts.dasm->pcshift; offs_t limit = opts.basepc + pclength; - offs_t pc_mask; - if(!limit) - pc_mask = 0xffffffff; - else { - for(pc_mask = 2; pc_mask && pc_mask < limit; pc_mask *= 2); - pc_mask--; - } + offs_t pc_mask = limit ? util::make_bitmask<offs_t>(32 - count_leading_zeros_32(limit - 1)) : 0xffffffff; - // Compute the page warparound + // Compute the page wraparound offs_t page_mask = flags & util::disasm_interface::PAGED ? (1 << disasm->page_address_bits()) - 1 : 0; // Next pc computation lambdas @@ -1160,7 +1391,7 @@ int main(int argc, char *argv[]) } // Compute the shift amount from pc delta to granularity-sized elements - u32 granularity_shift = 31 - count_leading_zeros(disasm->opcode_alignment()); + u32 granularity_shift = 31 - count_leading_zeros_32(disasm->opcode_alignment()); // Number of pc steps to disassemble u32 count = pclength; @@ -1170,8 +1401,8 @@ int main(int argc, char *argv[]) // pc to string conversion std::function<std::string (offs_t pc)> pc_to_string; - int aw = 32 - count_leading_zeros(pc_mask); - bool is_octal = false; // Parameter? Per-cpu config? + int aw = 32 - count_leading_zeros_32(pc_mask); + bool is_octal = opts.octal; // Parameter? Per-cpu config? if((flags & util::disasm_interface::PAGED2LEVEL) == util::disasm_interface::PAGED2LEVEL) { int bits1 = disasm->page_address_bits(); int bits2 = disasm->page2_address_bits(); @@ -1292,62 +1523,122 @@ int main(int argc, char *argv[]) max_len >>= granularity_shift; std::function<std::string (offs_t pc, offs_t size)> dump_raw_bytes; - switch(granularity) { - case 1: - dump_raw_bytes = [step = disasm->opcode_alignment(), next_pc, base_buffer](offs_t pc, offs_t size) -> std::string { - std::string result = ""; - for(offs_t i=0; i != size; i++) { - if(i) - result += ' '; - result += util::string_format("%02x", base_buffer.r8(pc)); - pc = next_pc(pc, step); - } - return result; - }; - max_len = (max_len * 3) - 1; - break; - - case 2: - dump_raw_bytes = [step = disasm->opcode_alignment(), next_pc, base_buffer](offs_t pc, offs_t size) -> std::string { - std::string result = ""; - for(offs_t i=0; i != size; i++) { - if(i) - result += ' '; - result += util::string_format("%04x", base_buffer.r16(pc)); - pc = next_pc(pc, step); - } - return result; - }; - max_len = (max_len * 5) - 1; - break; - - case 4: - dump_raw_bytes = [step = disasm->opcode_alignment(), next_pc, base_buffer](offs_t pc, offs_t size) -> std::string { - std::string result = ""; - for(offs_t i=0; i != size; i++) { - if(i) - result += ' '; - result += util::string_format("%08x", base_buffer.r32(pc)); - pc = next_pc(pc, step); - } - return result; - }; - max_len = (max_len * 9) - 1; - break; - - case 8: - dump_raw_bytes = [step = disasm->opcode_alignment(), next_pc, base_buffer](offs_t pc, offs_t size) -> std::string { - std::string result = ""; - for(offs_t i=0; i != size; i++) { - if(i) - result += ' '; - result += util::string_format("%016x", base_buffer.r64(pc)); - pc = next_pc(pc, step); - } - return result; - }; - max_len = (max_len * 17) - 1; - break; + if(is_octal) { + switch(granularity) { + case 1: + dump_raw_bytes = [step = disasm->opcode_alignment(), &next_pc, &base_buffer](offs_t pc, offs_t size) -> std::string { + std::string result = ""; + for(offs_t i=0; i != size; i++) { + if(i) + result += ' '; + result += util::string_format("%03o", base_buffer.r8(pc)); + pc = next_pc(pc, step); + } + return result; + }; + max_len = (max_len * 4) - 1; + break; + + case 2: + dump_raw_bytes = [step = disasm->opcode_alignment(), &next_pc, &base_buffer](offs_t pc, offs_t size) -> std::string { + std::string result = ""; + for(offs_t i=0; i != size; i++) { + if(i) + result += ' '; + result += util::string_format("%06o", base_buffer.r16(pc)); + pc = next_pc(pc, step); + } + return result; + }; + max_len = (max_len * 7) - 1; + break; + + case 4: + dump_raw_bytes = [step = disasm->opcode_alignment(), &next_pc, &base_buffer](offs_t pc, offs_t size) -> std::string { + std::string result = ""; + for(offs_t i=0; i != size; i++) { + if(i) + result += ' '; + result += util::string_format("%011o", base_buffer.r32(pc)); + pc = next_pc(pc, step); + } + return result; + }; + max_len = (max_len * 12) - 1; + break; + + case 8: + dump_raw_bytes = [step = disasm->opcode_alignment(), &next_pc, &base_buffer](offs_t pc, offs_t size) -> std::string { + std::string result = ""; + for(offs_t i=0; i != size; i++) { + if(i) + result += ' '; + result += util::string_format("%022o", base_buffer.r64(pc)); + pc = next_pc(pc, step); + } + return result; + }; + max_len = (max_len * 23) - 1; + break; + } + } else { + switch(granularity) { + case 1: + dump_raw_bytes = [step = disasm->opcode_alignment(), &next_pc, &base_buffer](offs_t pc, offs_t size) -> std::string { + std::string result = ""; + for(offs_t i=0; i != size; i++) { + if(i) + result += ' '; + result += util::string_format("%02x", base_buffer.r8(pc)); + pc = next_pc(pc, step); + } + return result; + }; + max_len = (max_len * 3) - 1; + break; + + case 2: + dump_raw_bytes = [step = disasm->opcode_alignment(), &next_pc, &base_buffer](offs_t pc, offs_t size) -> std::string { + std::string result = ""; + for(offs_t i=0; i != size; i++) { + if(i) + result += ' '; + result += util::string_format("%04x", base_buffer.r16(pc)); + pc = next_pc(pc, step); + } + return result; + }; + max_len = (max_len * 5) - 1; + break; + + case 4: + dump_raw_bytes = [step = disasm->opcode_alignment(), &next_pc, &base_buffer](offs_t pc, offs_t size) -> std::string { + std::string result = ""; + for(offs_t i=0; i != size; i++) { + if(i) + result += ' '; + result += util::string_format("%08x", base_buffer.r32(pc)); + pc = next_pc(pc, step); + } + return result; + }; + max_len = (max_len * 9) - 1; + break; + + case 8: + dump_raw_bytes = [step = disasm->opcode_alignment(), &next_pc, &base_buffer](offs_t pc, offs_t size) -> std::string { + std::string result = ""; + for(offs_t i=0; i != size; i++) { + if(i) + result += ' '; + result += util::string_format("%016x", base_buffer.r64(pc)); + pc = next_pc(pc, step); + } + return result; + }; + max_len = (max_len * 17) - 1; + break; + } } if(opts.flipped) { @@ -1366,7 +1657,75 @@ int main(int argc, char *argv[]) util::stream_format(std::cout, "%s: %-*s %s\n", tf(pc_to_string(l.pc)), max_len, tf(dump_raw_bytes(l.pc, l.size >> granularity_shift)), tf(l.dasm)); } - free(data); - return 0; } + + +int main(int argc, char *argv[]) +{ + // Parse options first + options opts; + if(parse_options(argc, argv, &opts)) + return 1; + + // Load the file + void *data = nullptr; + util::random_read::ptr file; + u64 length = 0; + if(std::strcmp(opts.filename, "-") != 0) { + osd_file::ptr f; + std::error_condition filerr = osd_file::open(std::string(opts.filename), OPEN_FLAG_READ, f, length); + if(filerr) { + std::fprintf(stderr, "Error opening file '%s' (%s)\n", opts.filename, filerr.message().c_str()); + return 1; + } + file = util::osd_file_read(std::move(f)); + if(!file) { + std::fprintf(stderr, "Error when opening file '%s'\n", opts.filename); + return 1; + } + } + else + { +#ifdef _WIN32 + if (_setmode(_fileno(stdin), _O_BINARY) == -1) { +#else + if (!std::freopen(nullptr, "rb", stdin)) { +#endif + std::fprintf(stderr, "Error reopening stdin in binary mode\n"); + return 1; + } + std::size_t allocated = 0x1000; + data = std::malloc(allocated); + while(!std::ferror(stdin) && !std::feof(stdin)) { + if(length == allocated) { + allocated <<= 1; + data = std::realloc(data, allocated); + } + if(!data) { + std::fprintf(stderr, "Error allocating buffer\n"); + return 1; + } + + length += std::fread((u8 *)data + length, 1, allocated - length, stdin); + } + if(!length || (std::ferror(stdin) && !std::feof(stdin))) { + std::fprintf(stderr, "Error reading from stdin\n"); + std::free(data); + return 1; + } + file = util::ram_read(data, length); + if(!file) { + std::fprintf(stderr, "Error opening stdin as file\n"); + std::free(data); + return 1; + } + } + + int result = disasm_file(*file, length, opts); + + file.reset(); + std::free(data); + + return result; +} |