diff --git a/src/tools/aueffectutil-Info.plist b/src/tools/aueffectutil-Info.plist deleted file mode 100644 index e509415..0000000 --- a/src/tools/aueffectutil-Info.plist +++ /dev/null @@ -1,45 +0,0 @@ - - - - - CFBundleDisplayName - AUEffectUtil - CFBundleDocumentTypes - - - CFBundleTypeExtensions - - aueffect - - CFBundleTypeName - AUEffect - CFBundleTypeOSTypes - - CFBundleTypeRole - Editor - NSDocumentClass - AUEffectDocument - - - CFBundleTypeExtensions - - aupreset - - CFBundleTypeName - AudioUnit Preset - CFBundleTypeOSTypes - - CFBundleTypeRole - Editor - NSDocumentClass - AUEffectDocument - - - CFBundleIdentifier - org.mamedev.aueffectutil - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - AUEffectUtil - - diff --git a/src/tools/aueffectutil.mm b/src/tools/aueffectutil.mm deleted file mode 100644 index 661800a..0000000 --- a/src/tools/aueffectutil.mm +++ /dev/null @@ -1,1076 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Vas Crabb -#import -#import -#import -#import -#import -#import -#import -#import -#import - -#include -#include - -#include - - -#ifdef MAC_OS_X_VERSION_MAX_ALLOWED - -#if MAC_OS_X_VERSION_MAX_ALLOWED < 1060 - -typedef ComponentDescription AudioComponentDescription; - -@protocol NSApplicationDelegate -@end - -@protocol NSWindowDelegate -@end - -#endif // MAC_OS_X_VERSION_MAX_ALLOWED < 1060 - -#endif // MAC_OS_X_VERSION_MAX_ALLOWED - - -struct EffectInfo -{ - Component component; - OSType type; - OSType subtype; - OSType manufacturer; -}; - - -static NSString *const AUEffectUtilErrorDomain = @"AUEffectUtilErrorDomain"; - -static NSString *const AUEffectDocumentType = @"AUEffect"; -static NSString *const AUPresetDocumentType = @"AudioUnit Preset"; - -static NSString *const ComponentTypeKey = @"ComponentType"; -static NSString *const ComponentSubTypeKey = @"ComponentSubType"; -static NSString *const ComponentManufacturerKey = @"ComponentManufacturer"; -static NSString *const ClassInfoKey = @"ClassInfo"; -static NSString *const ForceGenericViewKey = @"ForceGenericView"; -static NSString *const WindowFrameKey = @"WindowFrame"; - - -static void UpdateChangeCountCallback( - void *userData, - void *object, - AudioUnitEvent const *inEvent, - UInt64 inEventHostTime, - AudioUnitParameterValue inParameterValue) -{ - [(NSDocument *)userData updateChangeCount:NSChangeDone]; -} - - -@interface AUEffectDocument : NSDocument -{ - IBOutlet NSWindow *window; - IBOutlet NSButton *genericViewButton; - IBOutlet NSPopUpButton *presetButton; - NSView *view; - NSSize headerSize; - CFArrayRef presets; - AUParameterListenerRef listener; - BOOL forceGenericView; - NSString *restoreFrame; - - AudioComponentDescription description; - AUGraph graph; - AUNode outputNode, sourceNode, effectNode; - AudioUnit outputUnit, sourceUnit, effectUnit; -} - -- (void)dealloc; - -- (void)makeWindowControllers; -- (BOOL)readFromData:(NSData *)data ofType:(NSString *)type error:(NSError **)error; -- (NSData *)dataOfType:(NSString *)type error:(NSError **)error; - -- (IBAction)toggleGenericView:(id)sender; -- (IBAction)loadPreset:(id)sender; - -- (void)viewFrameDidChange:(NSNotification *)notification; - -@end - -@implementation AUEffectDocument - -- (void)loadEffectUI { - if ((0 == effectNode) || !window) - return; - - BOOL customViewValid = NO; - OSStatus status; - UInt32 uiDescSize; - AudioUnitCocoaViewInfo *viewInfo; - status = AudioUnitGetPropertyInfo( - effectUnit, - kAudioUnitProperty_CocoaUI, - kAudioUnitScope_Global, - 0, - &uiDescSize, - NULL); - UInt32 const uiClassCount = 1 + ((uiDescSize - sizeof(*viewInfo)) / sizeof(viewInfo->mCocoaAUViewClass[0])); - if ((noErr == status) && (0 < uiClassCount)) - { - viewInfo = (AudioUnitCocoaViewInfo *)malloc(uiDescSize); - status = AudioUnitGetProperty(effectUnit, - kAudioUnitProperty_CocoaUI, - kAudioUnitScope_Global, - 0, - viewInfo, - &uiDescSize); - if (noErr == status) - { - NSBundle *const bundle = [NSBundle bundleWithPath:[(NSURL *)viewInfo->mCocoaAUViewBundleLocation path]]; - Class const viewClass = [bundle classNamed:(NSString *)viewInfo->mCocoaAUViewClass[0]]; - if (viewClass - && [viewClass conformsToProtocol:@protocol(AUCocoaUIBase)] - && [viewClass instancesRespondToSelector:@selector(uiViewForAudioUnit:withSize:)]) - { - customViewValid = YES; - if (!forceGenericView) - { - id const factory = [[viewClass alloc] init]; - view = [factory uiViewForAudioUnit:effectUnit - withSize:[[window contentView] bounds].size]; - [factory release]; - } - } - CFRelease(viewInfo->mCocoaAUViewBundleLocation); - for (UInt32 i = 0; i < uiClassCount; i++) - CFRelease(viewInfo->mCocoaAUViewClass[i]); - } - free(viewInfo); - } - if (!view) - { - view = [[[AUGenericView alloc] initWithAudioUnit:effectUnit] autorelease]; - [(AUGenericView *)view setShowsExpertParameters:YES]; - } - - [view setAutoresizingMask:NSViewNotSizable]; - [view setFrameOrigin:NSMakePoint(0, 0)]; - NSRect const oldFrame = [window frame]; - NSRect const desired = [window frameRectForContentRect:[view frame]]; - NSRect const newFrame = NSMakeRect(oldFrame.origin.x, - oldFrame.origin.y + oldFrame.size.height - headerSize.height - desired.size.height, - desired.size.width, - headerSize.height + desired.size.height); - [window setFrame:newFrame display:YES animate:NO]; - [[window contentView] addSubview:view]; - [view setPostsFrameChangedNotifications:YES]; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(viewFrameDidChange:) - name:NSViewFrameDidChangeNotification - object:view]; - - [genericViewButton setEnabled:customViewValid]; - if (!customViewValid) - { - forceGenericView = YES; - [genericViewButton setState:NSOnState]; - } - - CFIndex const presetCount = (NULL != presets) ? CFArrayGetCount(presets) : 0; - [presetButton setEnabled:(0 < presetCount)]; - while (1 < [presetButton numberOfItems]) - [presetButton removeItemAtIndex:1]; - for (CFIndex i = 0; i < presetCount; i++) - { - AUPreset const *preset = (AUPreset const*)CFArrayGetValueAtIndex(presets, i); - NSMenuItem const *item = [[presetButton menu] addItemWithTitle:(NSString *)preset->presetName - action:@selector(loadPreset:) - keyEquivalent:@""]; - [item setTarget:self]; - [item setTag:i]; - } -} - -- (id)init { - if (!(self = [super init])) - return nil; - - window = nil; - genericViewButton = nil; - presetButton = nil; - view = nil; - presets = NULL; - listener = NULL; - forceGenericView = NO; - restoreFrame = nil; - - description.componentType = description.componentSubType = description.componentManufacturer = 0; - description.componentFlags = description.componentFlagsMask = 0; - graph = NULL; - outputNode = sourceNode = effectNode = 0; - - AudioComponentDescription const outputDesc = { kAudioUnitType_Output, - kAudioUnitSubType_DefaultOutput, - kAudioUnitManufacturer_Apple, - 0, - 0, }; - AudioComponentDescription const sourceDesc = { kAudioUnitType_Generator, - kAudioUnitSubType_AudioFilePlayer, - kAudioUnitManufacturer_Apple, - 0, - 0, }; - if ((noErr != NewAUGraph(&graph)) - || (noErr != AUGraphAddNode(graph, &outputDesc, &outputNode)) - || (noErr != AUGraphAddNode(graph, &sourceDesc, &sourceNode)) - || (noErr != AUGraphOpen(graph)) - || (noErr != AUGraphNodeInfo(graph, outputNode, NULL, &outputUnit)) - || (noErr != AUGraphNodeInfo(graph, sourceNode, NULL, &sourceUnit)) - || (noErr != AUGraphInitialize(graph))) - { - [self release]; - return nil; - } - - return self; -} - -- (void)dealloc { - if (presets) - CFRelease(presets); - - if (listener) - AUListenerDispose(listener); - - if (restoreFrame) - [restoreFrame release]; - - if (graph) - { - AUGraphClose(graph); - DisposeAUGraph(graph); - } - - [super dealloc]; -} - -- (void)makeWindowControllers { - genericViewButton = [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 100, 18)]; - [genericViewButton setAutoresizingMask:NSViewNotSizable]; - [[genericViewButton cell] setControlSize:NSSmallControlSize]; - [genericViewButton setButtonType:NSSwitchButton]; - [genericViewButton setBordered:NO]; - [genericViewButton setAllowsMixedState:NO]; - [genericViewButton setState:(forceGenericView ? NSOnState : NSOffState)]; - [genericViewButton setTitle:@"Use generic editor view"]; - [genericViewButton setAction:@selector(toggleGenericView:)]; - [genericViewButton setTarget:self]; - [genericViewButton sizeToFit]; - - 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 setTitle:@"Load preset"]; - [[[presetButton menu] addItemWithTitle:@"Load preset" action:NULL keyEquivalent:@""] setHidden:YES]; - [presetButton sizeToFit]; - - CGFloat const controlWidth = MAX(NSWidth([genericViewButton frame]), NSWidth([presetButton frame])); - NSRect const presetFrame = NSMakeRect( - 17, - 8, - controlWidth, - NSHeight([presetButton frame])); - NSRect const genericViewFrame = NSMakeRect( - 17, - NSMaxY(presetFrame) + 9, - controlWidth, - NSHeight([genericViewButton frame])); - [genericViewButton setFrame:genericViewFrame]; - [presetButton setFrame:presetFrame]; - - headerSize = NSMakeSize((2 * 17) + controlWidth, 18 + NSMaxY(genericViewFrame)); - NSView *const container = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, headerSize.width, headerSize.height)]; - [container setAutoresizingMask:(NSViewMinXMargin | NSViewMaxXMargin | NSViewMinYMargin)]; - [container addSubview:genericViewButton]; - [genericViewButton release]; - [container addSubview:presetButton]; - [presetButton release]; - - window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, headerSize.width, headerSize.height) - styleMask:(NSTitledWindowMask | - NSClosableWindowMask | - NSMiniaturizableWindowMask) - backing:NSBackingStoreBuffered - defer:YES]; - [window setReleasedWhenClosed:NO]; - [window setDelegate:self]; - [window setTitle:@"Effect"]; - [[window contentView] addSubview:container]; - [container release]; - [self setWindow:window]; - - NSWindowController *const controller = [[NSWindowController alloc] initWithWindow:window]; - [self addWindowController:controller]; - [controller release]; - [window release]; - - [self loadEffectUI]; - if (restoreFrame) - { - [window setFrameFromString:restoreFrame]; - } - else - { - NSRect const available = [[NSScreen mainScreen] visibleFrame]; - NSRect frame = [window frame]; - frame.origin.x = (NSWidth(available) - NSWidth(frame)) / 4; - frame.origin.y = (NSHeight(available) - NSHeight(frame)) * 3 / 4; - [window setFrame:frame display:YES animate:NO]; - } -} - -- (BOOL)readFromData:(NSData *)data ofType:(NSString *)type error:(NSError **)error { - OSStatus status; - UInt32 propertySize; - - BOOL const hasWrapper = [type isEqualToString:AUEffectDocumentType]; - if (!hasWrapper && ![type isEqualToString:AUPresetDocumentType]) - { - if (error) - { - NSString *const message = [NSString stringWithFormat:@"Unsupported document type %@", type]; - NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message, NSLocalizedDescriptionKey, - nil]; - *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info]; - } - return NO; - } - - NSString *errDesc = nil; - id const desc = [NSPropertyListSerialization propertyListFromData:data - mutabilityOption:0 - format:NULL - errorDescription:&errDesc]; - if (!desc || ![desc isKindOfClass:[NSDictionary class]] || errDesc) - { - if (error) - { - NSString *const message = [NSString stringWithFormat:@"Error in file format (%@)", errDesc]; - NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message, NSLocalizedDescriptionKey, - nil]; - *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info]; - } - if (errDesc) - [errDesc release]; - return NO; - } - - id const typeValue = [desc objectForKey:(hasWrapper ? ComponentTypeKey : (NSString *)CFSTR(kAUPresetTypeKey))]; - id const subtypeValue = [desc objectForKey:(hasWrapper ? ComponentSubTypeKey : (NSString *)CFSTR(kAUPresetSubtypeKey))]; - id const manufacturerValue = [desc objectForKey:(hasWrapper ? ComponentManufacturerKey : (NSString *)CFSTR(kAUPresetManufacturerKey))]; - if (!typeValue || ![typeValue isKindOfClass:[NSNumber class]] - || !subtypeValue || ![subtypeValue isKindOfClass:[NSNumber class]] - || !manufacturerValue || ![manufacturerValue isKindOfClass:[NSNumber class]] - || ([typeValue unsignedLongValue] != kAudioUnitType_Effect)) - { - if (error) - { - NSString *const message = @"Error in effect description file format"; - NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message, NSLocalizedDescriptionKey, - nil]; - *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info]; - } - return NO; - } - - if (presets) - { - CFRelease(presets); - presets = NULL; - } - if (listener) - { - AUListenerDispose(listener); - listener = NULL; - } - if (view) - { - [[NSNotificationCenter defaultCenter] removeObserver:self - name:NSViewFrameDidChangeNotification - object:nil]; - [view removeFromSuperview]; - view = nil; - } - if (0 != effectNode) - { - view = nil; - AUGraphRemoveNode(graph, effectNode); - effectNode = 0; - } - - description.componentType = [typeValue longValue]; - description.componentSubType = [subtypeValue longValue]; - description.componentManufacturer = [manufacturerValue longValue]; - status = noErr; - status = AUGraphClearConnections(graph); - if (noErr == status) - status = AUGraphAddNode(graph, &description, &effectNode); - if (noErr == status) - status = AUGraphNodeInfo(graph, effectNode, NULL, &effectUnit); - if (noErr == status) - status = AUGraphConnectNodeInput(graph, sourceNode, 0, effectNode, 0); - if (noErr == status) - status = AUGraphConnectNodeInput(graph, effectNode, 0, outputNode, 0); - if (noErr == status) - status = AUGraphUpdate(graph, NULL); - if (noErr != status) - { - if (error) - { - NSString * const message = @"Error encountered while configuring AudioUnit graph"; - NSError *const underlying = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil]; - NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message, NSLocalizedDescriptionKey, - underlying, NSUnderlyingErrorKey, - nil]; - *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info]; - } - return NO; - } - - CFPropertyListRef const classInfo = (CFPropertyListRef)(hasWrapper ? [desc objectForKey:ClassInfoKey] : desc); - if (classInfo) - { - AudioUnitParameter change = { effectUnit, kAUParameterListener_AnyParameter, 0, 0 }; - status = AudioUnitSetProperty( - effectUnit, - kAudioUnitProperty_ClassInfo, - kAudioUnitScope_Global, - 0, - &classInfo, - sizeof(classInfo)); - if (noErr == status) - status = AUParameterListenerNotify(NULL, NULL, &change); - if (noErr != status) - { - if (error) - { - NSString * const message = @"Error configuring effect"; - NSError *const underlying = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil]; - NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message, NSLocalizedDescriptionKey, - underlying, NSUnderlyingErrorKey, - nil]; - *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info]; - } - return NO; - } - } - - propertySize = 0; - status = AudioUnitGetPropertyInfo( - effectUnit, - kAudioUnitProperty_ParameterList, - kAudioUnitScope_Global, - 0, - &propertySize, - NULL); - if (noErr != status) - { - if (error) - { - NSString * const message = @"Error getting effect parameters"; - NSError *const underlying = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil]; - NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message, NSLocalizedDescriptionKey, - underlying, NSUnderlyingErrorKey, - nil]; - *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info]; - } - return NO; - } - UInt32 const paramCount = propertySize / sizeof(AudioUnitParameterID); - if (0U < paramCount) - { - status = AUEventListenerCreate( - UpdateChangeCountCallback, - self, - CFRunLoopGetCurrent(), - kCFRunLoopDefaultMode, - 0.05, - 0.05, - &listener); - if (noErr != status) - { - if (error) - { - NSString * const message = @"Error creating AudioUnit event listener"; - NSError *const underlying = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil]; - NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message, NSLocalizedDescriptionKey, - underlying, NSUnderlyingErrorKey, - nil]; - *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info]; - } - return NO; - } - AudioUnitParameterID *const params = (AudioUnitParameterID *)malloc(propertySize); - AudioUnitGetProperty( - effectUnit, - kAudioUnitProperty_ParameterList, - kAudioUnitScope_Global, - 0, - params, - &propertySize); - if (noErr != status) - { - free(params); - if (error) - { - NSString * const message = @"Error getting effect parameters"; - NSError *const underlying = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil]; - NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message, NSLocalizedDescriptionKey, - underlying, NSUnderlyingErrorKey, - nil]; - *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info]; - } - return NO; - } - for (UInt32 i = 0; (i < paramCount) && (noErr == status); i++) - { - AudioUnitEvent event; - event.mEventType = kAudioUnitEvent_ParameterValueChange; - event.mArgument.mParameter.mAudioUnit = effectUnit; - event.mArgument.mParameter.mParameterID = params[i]; - event.mArgument.mParameter.mScope = kAudioUnitScope_Global; - event.mArgument.mParameter.mElement = 0; - status = AUEventListenerAddEventType(listener, self, &event); - } - free(params); - if (noErr != status) - { - free(params); - if (error) - { - NSString * const message = @"Error getting effect parameters"; - NSError *const underlying = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil]; - NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message, NSLocalizedDescriptionKey, - underlying, NSUnderlyingErrorKey, - nil]; - *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info]; - } - return NO; - } - } - - propertySize = sizeof(presets); - status = AudioUnitGetProperty( - effectUnit, - kAudioUnitProperty_FactoryPresets, - kAudioUnitScope_Global, - 0, - &presets, - &propertySize); - if ((noErr != status) && presets) - { - CFRelease(presets); - presets = NULL; - } - - if (hasWrapper) - { - if ([desc objectForKey:ForceGenericViewKey] - && [[desc objectForKey:ForceGenericViewKey] respondsToSelector:@selector(boolValue)]) - { - forceGenericView = [[desc objectForKey:ForceGenericViewKey] boolValue]; - [genericViewButton setState:(forceGenericView ? NSOnState : NSOffState)]; - } - if ([desc objectForKey:WindowFrameKey] - && [[desc objectForKey:WindowFrameKey] isKindOfClass:[NSString class]]) - { - if (restoreFrame) - [restoreFrame release]; - restoreFrame = [[NSString alloc] initWithString:[desc objectForKey:WindowFrameKey]]; - } - } - - [self loadEffectUI]; - - return YES; -} - -- (NSData *)dataOfType:(NSString *)type error:(NSError **)error { - CFPropertyListRef classInfo; - UInt32 infoSize = sizeof(classInfo); - OSStatus const status = AudioUnitGetProperty( - effectUnit, - kAudioUnitProperty_ClassInfo, - kAudioUnitScope_Global, - 0, - &classInfo, - &infoSize); - if (noErr != status) - { - if (NULL != error) - { - NSString const *message = @"Error getting effect settings"; - NSError const *underlying = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil]; - NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message, NSLocalizedDescriptionKey, - underlying, NSUnderlyingErrorKey, - nil]; - *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info]; - } - return nil; - } - NSDictionary *desc = nil; - if ([type isEqualToString:AUEffectDocumentType]) - { - NSNumber const *typeVal = [NSNumber numberWithUnsignedLong:description.componentType]; - NSNumber const *subtypeVal = [NSNumber numberWithUnsignedLong:description.componentSubType]; - NSNumber const *manufacturerVal = [NSNumber numberWithUnsignedLong:description.componentManufacturer]; - NSNumber const *forceGenericViewVal = [NSNumber numberWithBool:forceGenericView]; - NSString const *windowFrameVal = [window stringWithSavedFrame]; - desc = [NSDictionary dictionaryWithObjectsAndKeys:typeVal, ComponentTypeKey, - subtypeVal, ComponentSubTypeKey, - manufacturerVal, ComponentManufacturerKey, - classInfo, ClassInfoKey, - forceGenericViewVal, ForceGenericViewKey, - windowFrameVal, WindowFrameKey, - nil]; - } - else if ([type isEqualToString:AUPresetDocumentType]) - { - desc = [NSDictionary dictionaryWithDictionary:(NSDictionary *)classInfo]; - } - CFRelease(classInfo); - if (!desc) - { - NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:@"Unsupported document type", NSLocalizedDescriptionKey, - nil]; - *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info]; - return nil; - } - - NSString *errDesc = nil; - NSData *const data = [NSPropertyListSerialization dataFromPropertyList:desc - format:NSPropertyListXMLFormat_v1_0 - errorDescription:&errDesc]; - if (!data || errDesc) - { - if (error) - { - NSString *message; - if (errDesc) - message = [NSString stringWithFormat:@"Error serialising effect settings: %@", errDesc]; - 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]); - if (view) - { - [[NSNotificationCenter defaultCenter] removeObserver:self - name:NSViewFrameDidChangeNotification - object:nil]; - [view removeFromSuperview]; - view = nil; - } - if (0 != effectNode) - [self loadEffectUI]; -} - -- (IBAction)loadPreset:(id)sender { - OSStatus status; - - CFIndex const idx = [sender tag]; - CFIndex const total = (NULL == presets) ? 0 : CFArrayGetCount(presets); - if ((0 > idx) || (total <= idx)) - { - NSAlert const *alert = [[NSAlert alloc] init]; - [alert setMessageText:@"Invalid preset selected"]; - [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]; - return; - } - - AUPreset const *preset = (AUPreset const *)CFArrayGetValueAtIndex(presets, idx); - status = AudioUnitSetProperty( - effectUnit, - kAudioUnitProperty_PresentPreset, - kAudioUnitScope_Global, - 0, - preset, - sizeof(AUPreset)); - if (noErr != status) - { - NSAlert const *alert = [[NSAlert alloc] init]; - [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]; - return; - } - - AudioUnitParameter change = { effectUnit, kAUParameterListener_AnyParameter, 0, 0 }; - status = AUParameterListenerNotify(NULL, NULL, &change); - if (noErr != status) - { - NSAlert const *alert = [[NSAlert alloc] init]; - [alert setMessageText:[NSString stringWithFormat:@"Error notifying of parameter changes for preset %@", - preset->presetName]]; - [alert setInformativeText:[NSString stringWithFormat:@"Error %ld encountered while sending notification", - (long)status]]; - [alert beginSheetModalForWindow:window modalDelegate:nil didEndSelector:NULL contextInfo:NULL]; - return; - } -} - -- (void)viewFrameDidChange:(NSNotification *)notification { - NSRect const oldFrame = [window frame]; - NSRect const desired = [window frameRectForContentRect:[[notification object] frame]]; - NSRect const newFrame = NSMakeRect( - oldFrame.origin.x, - oldFrame.origin.y + oldFrame.size.height - headerSize.height- desired.size.height, - desired.size.width, - headerSize.height + desired.size.height); - [window setFrame:newFrame display:YES animate:NO]; -} - -@end - - -@interface AUEffectUtilAppDelegate : NSObject -{ - EffectInfo *effects; - - IBOutlet NSMenu *newEffectMenu; -} - -- (id)init; -- (void)dealloc; - -- (IBAction)newEffect:(id)sender; - -- (void)applicationWillFinishLaunching:(NSNotification *)notification; -- (void)applicationDidFinishLaunching:(NSNotification *)notification; -- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender; - -@end - -@implementation AUEffectUtilAppDelegate - -- (void)appendApplicationMenu:(NSMenu *)parent { - NSMenuItem *item; - NSMenu *submenu; - NSString *const appName = [(NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle()) objectForKey:@"CFBundleName"]; - - NSMenu *const menu = [[NSMenu alloc] initWithTitle:@"Application"]; - item = [parent addItemWithTitle:@"Application" action:NULL keyEquivalent:@""]; - [parent setSubmenu:menu forItem:item]; - [menu release]; - [menu setValue:@"NSAppleMenu" forKey:@"name"]; - - item = [menu addItemWithTitle:[NSString stringWithFormat:@"About %@", appName] action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; - [item setTarget:NSApp]; - - [menu addItem:[NSMenuItem separatorItem]]; - - item = [menu addItemWithTitle:@"Services" action:NULL keyEquivalent:@""]; - submenu = [[NSMenu alloc] initWithTitle:@"Services"]; - [menu setSubmenu:submenu forItem:item]; - [submenu release]; - [NSApp setServicesMenu:submenu]; - - [menu addItem:[NSMenuItem separatorItem]]; - - 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 = [menu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; - - [menu addItem:[NSMenuItem separatorItem]]; - - item = [menu addItemWithTitle:[NSString stringWithFormat:@"Quit %@", appName] action:@selector(terminate:) keyEquivalent:@"q"]; - [item setTarget:NSApp]; -} - -- (void)appendFileMenu:(NSMenu *)parent { - NSMenuItem *item; - - NSMenu *const menu = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"File"]; - item = [parent addItemWithTitle:@"File" action:NULL keyEquivalent:@""]; - [parent setSubmenu:menu forItem:item]; - [menu release]; - - item = [menu addItemWithTitle:@"New" action:NULL keyEquivalent:@""]; - newEffectMenu = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"New"]; - [menu setSubmenu:newEffectMenu forItem:item]; - [newEffectMenu release]; - item = [menu addItemWithTitle:[NSString stringWithFormat:@"Open%C", (unichar)0x2026] action:@selector(openDocument:) keyEquivalent:@"o"]; - - [menu addItem:[NSMenuItem separatorItem]]; - - item = [menu addItemWithTitle:@"Close" action:@selector(performClose:) keyEquivalent:@"w"]; - item = [menu addItemWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:@"s"]; - item = [menu addItemWithTitle:[NSString stringWithFormat:@"Save As%C", (unichar)0x2026] action:@selector(saveDocumentAs:) keyEquivalent:@"S"]; - item = [menu addItemWithTitle:@"Save All" action:@selector(saveAllDocuments:) keyEquivalent:@""]; - item = [menu addItemWithTitle:@"Revert to Saved" action:@selector(revertDocumentToSaved:) keyEquivalent:@"u"]; -} - -- (void)appendEditMenu:(NSMenu *)parent { - NSMenuItem *item; - - NSMenu *const menu = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"Edit"]; - item = [parent addItemWithTitle:@"Edit" action:NULL keyEquivalent:@""]; - [parent setSubmenu:menu forItem:item]; - [menu release]; - - item = [menu addItemWithTitle:@"Undo" action:@selector(undo:) keyEquivalent:@"z"]; - item = [menu addItemWithTitle:@"Redo" action:@selector(redo:) keyEquivalent:@"Z"]; - - [menu addItem:[NSMenuItem separatorItem]]; - - item = [menu addItemWithTitle:@"Cut" action:@selector(cut:) keyEquivalent:@"x"]; - item = [menu addItemWithTitle:@"Copy" action:@selector(copy:) keyEquivalent:@"c"]; - item = [menu addItemWithTitle:@"Paste" action:@selector(paste:) keyEquivalent:@"v"]; - item = [menu addItemWithTitle:@"Delete" action:@selector(delete:) keyEquivalent:@""]; - item = [menu addItemWithTitle:@"Select All" action:@selector(selectAll:) keyEquivalent:@"a"]; -} - -- (void)appendWindowMenu:(NSMenu *)parent { - NSMenuItem *item; - - NSMenu *const menu = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"Window"]; - item = [parent addItemWithTitle:@"Window" action:NULL keyEquivalent:@""]; - [parent setSubmenu:menu forItem:item]; - [menu release]; - [NSApp setWindowsMenu:menu]; - - item = [menu addItemWithTitle:@"Minimize" action:@selector(performMinimize:) keyEquivalent:@"m"]; - item = [menu addItemWithTitle:@"Zoom" action:@selector(performZoom:) keyEquivalent:@""]; - - [menu addItem:[NSMenuItem separatorItem]]; - - item = [menu addItemWithTitle:@"Bring All to Front" action:@selector(arrangeInFront:) keyEquivalent:@""]; -} - -- (void)appendHelpMenu:(NSMenu *)parent { - NSMenuItem *item; - NSString *const appName = [(NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle()) objectForKey:@"CFBundleName"]; - - NSMenu *const menu = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"Help"]; - item = [parent addItemWithTitle:@"Help" action:NULL keyEquivalent:@""]; - [parent setSubmenu:menu forItem:item]; - [menu release]; - [menu setValue:@"NSHelpMenu" forKey:@"name"]; - if ([NSApp respondsToSelector:@selector(setHelpMenu:)]) - [NSApp performSelector:@selector(setHelpMenu:) withObject:menu]; - - item = [menu addItemWithTitle:[NSString stringWithFormat:@"%@ Help", appName] action:@selector(showHelp:) keyEquivalent:@"?"]; -} - -- (id)init { - if (!(self = [super init])) - return nil; - effects = NULL; - return self; -} - -- (void)dealloc { - if (effects) - free(effects); - [super dealloc]; -} - -- (IBAction)newEffect:(id)sender { - int const index = [sender tag]; - if ((0 > index) || (0 == effects[index].component)) - { - NSAlert *const alert = [[NSAlert alloc] init]; - [alert setAlertStyle:NSWarningAlertStyle]; - [alert setMessageText:@"Invalid effect component"]; - [alert addButtonWithTitle:@"OK"]; - [alert runModal]; - [alert release]; - return; - } - - NSNumber *const typeValue = [NSNumber numberWithUnsignedLong:effects[index].type]; - NSNumber *const subtypeValue = [NSNumber numberWithUnsignedLong:effects[index].subtype]; - NSNumber *const manufacturerValue = [NSNumber numberWithUnsignedLong:effects[index].manufacturer]; - NSDictionary *const desc = [NSDictionary dictionaryWithObjectsAndKeys:typeValue, ComponentTypeKey, - subtypeValue, ComponentSubTypeKey, - manufacturerValue, ComponentManufacturerKey, - nil]; - NSString *errDesc = nil; - NSData *const data = [NSPropertyListSerialization dataFromPropertyList:desc - format:NSPropertyListXMLFormat_v1_0 - errorDescription:&errDesc]; - if (!data || errDesc) - { - NSAlert *const alert = [[NSAlert alloc] init]; - [alert setAlertStyle:NSWarningAlertStyle]; - [alert setMessageText:@"Error serialising properties for new effect"]; - if (errDesc) - [alert setInformativeText:[errDesc autorelease]]; - [alert addButtonWithTitle:@"OK"]; - [alert runModal]; - [alert release]; - return; - } - - NSError *err = nil; - AUEffectDocument *const document = [[AUEffectDocument alloc] init]; - if (!document || ![document readFromData:data ofType:AUEffectDocumentType error:&err]) - { - [document release]; - if (err) - { - [[NSAlert alertWithError:err] runModal]; - } - else - { - NSAlert *const alert = [[NSAlert alloc] init]; - [alert setAlertStyle:NSWarningAlertStyle]; - [alert setMessageText:@"Error creating new effect document"]; - [alert addButtonWithTitle:@"OK"]; - [alert runModal]; - [alert release]; - } - return; - } - - [document makeWindowControllers]; - [document showWindows]; - [[NSDocumentController sharedDocumentController] addDocument:document]; - [document release]; -} - -- (void)applicationWillFinishLaunching:(NSNotification *)notification { - NSMenu *const menubar = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"MainMenu"]; - [NSApp setMainMenu:menubar]; - [menubar release]; - [self appendApplicationMenu:menubar]; - [self appendFileMenu:menubar]; - [self appendEditMenu:menubar]; - [self appendWindowMenu:menubar]; - [self appendHelpMenu:menubar]; - - ProcessSerialNumber const serial = { 0, kCurrentProcess }; - OSStatus const status = TransformProcessType(&serial, kProcessTransformToForegroundApplication); - if (noErr != status) - { - NSLog(@"Error transforming to foreground application (%ld)", (long)status); - [NSApp terminate:self]; - } - else - { - [NSApp activateIgnoringOtherApps:YES]; - } -} - -- (void)applicationDidFinishLaunching:(NSNotification *)notification { - ComponentDescription effectFilter = { kAudioUnitType_Effect, 0, 0, 0, 0 }; - long const count = CountComponents(&effectFilter); - if (0 == count) - { - NSAlert *const alert = [[NSAlert alloc] init]; - [alert setAlertStyle:NSWarningAlertStyle]; - [alert setMessageText:@"No AudioUnit effects found"]; - [alert addButtonWithTitle:@"OK"]; - [alert runModal]; - [alert release]; - } - - std::vector > 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)) - { - ComponentDescription effectDesc; - Handle const nameHandle = NewHandle(4); - OSStatus const err = GetComponentInfo(effect, &effectDesc, nameHandle, NULL, NULL); - 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:@""]; - [item setTag:i]; - [item setTarget:self]; - CFRelease(name); - } - else - { - effects[i].component = 0; - failed.push_back(std::make_pair(effect, err)); - } - DisposeHandle(nameHandle); - } - - if (!failed.empty()) - { - NSString *const message = [NSString stringWithFormat:@"Failed to get info for %lu effect%s", - (unsigned long)failed.size(), - ((1U == failed.size()) ? "" : "s")]; - NSMutableString *const detail = [NSMutableString stringWithCapacity:(16 * failed.size())]; - std::vector >::const_iterator it = failed.begin(); - [detail appendFormat:@"%lu (%ld)", (unsigned long)it->first, (long)it->second]; - ++it; - while (failed.end() != it) - { - [detail appendFormat:@", %lu (%ld)", (unsigned long)it->first, (long)it->second]; - ++it; - } - NSAlert *const alert = [[NSAlert alloc] init]; - [alert setAlertStyle:NSWarningAlertStyle]; - [alert setMessageText:message]; - [alert setInformativeText:[NSString stringWithString:detail]]; - [alert addButtonWithTitle:@"OK"]; - [alert runModal]; - [alert release]; - } -} - -- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender { - return NO; -} - -@end - - -int main(int argc, char *argv[]) -{ - NSAutoreleasePool *pool; - - // Initialise NSApplication - pool = [[NSAutoreleasePool alloc] init]; - [NSApplication sharedApplication]; - AUEffectUtilAppDelegate *const delegate = [[AUEffectUtilAppDelegate alloc] init]; - [[NSApplication sharedApplication] setDelegate:delegate]; - [pool release]; - - // Let's go! - pool = [[NSAutoreleasePool alloc] init]; - [NSApp run]; - [delegate release]; - [pool release]; - return 0; -} diff --git a/src/tools/castool.cpp b/src/tools/castool.cpp deleted file mode 100644 index b5fa9cf..0000000 --- a/src/tools/castool.cpp +++ /dev/null @@ -1,227 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Miodrag Milanovic -/*************************************************************************** - - main.c - - Castool command line front end - - 27/03/2009 Initial version by Miodrag Milanovic - -***************************************************************************/ - -#include "formats/a26_cas.h" -#include "formats/ace_tap.h" -#include "formats/adam_cas.h" -#include "formats/apf_apt.h" -#include "formats/atom_tap.h" -#include "formats/cbm_tap.h" -#include "formats/cgen_cas.h" -#include "formats/coco_cas.h" -#include "formats/csw_cas.h" -#include "formats/fm7_cas.h" -#include "formats/fmsx_cas.h" -#include "formats/gtp_cas.h" -#include "formats/hect_tap.h" -#include "formats/kc_cas.h" -#include "formats/kim1_cas.h" -#include "formats/lviv_lvt.h" -#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" -#include "formats/primoptp.h" -#include "formats/rk_cas.h" -#include "formats/sc3000_bit.h" -#include "formats/sol_cas.h" -#include "formats/sorc_cas.h" -#include "formats/sord_cas.h" -#include "formats/spc1000_cas.h" -#include "formats/svi_cas.h" -#include "formats/thom_cas.h" -#include "formats/trs_cas.h" -#include "formats/tvc_cas.h" -#include "formats/tzx_cas.h" -#include "formats/uef_cas.h" -#include "formats/vg5k_cas.h" -#include "formats/vt_cas.h" -#include "formats/x07_cas.h" -#include "formats/x1_tap.h" -#include "formats/zx81_p.h" - -#include "corestr.h" -#include "ioprocs.h" -#include "osdcomm.h" - -#include -#include -#include -#include -#include -#include - - -struct SupportedCassetteFormats -{ - const char *name; - const cassette_image::Format * const *formats; - const char *desc; -}; - -const struct SupportedCassetteFormats formats[] = { - {"a26", a26_cassette_formats ,"Atari 2600 SuperCharger"}, - {"apf", apf_cassette_formats ,"APF Imagination Machine"}, - {"atom", atom_cassette_formats ,"Acorn Atom"}, - {"bbc", bbc_cassette_formats ,"Acorn BBC & Electron"}, - {"cbm", cbm_cassette_formats ,"Commodore 8-bit series"}, - {"cdt", cdt_cassette_formats ,"Amstrad CPC"}, - {"cgenie", cgenie_cassette_formats ,"EACA Colour Genie"}, - {"coco", coco_cassette_formats ,"Tandy Radio Shack Color Computer"}, - {"csw", csw_cassette_formats ,"Compressed Square Wave"}, - {"ddp", coleco_adam_cassette_formats ,"Coleco ADAM"}, - {"fm7", fm7_cassette_formats ,"Fujitsu FM-7"}, - {"fmsx", fmsx_cassette_formats ,"MSX"}, - {"gtp", gtp_cassette_formats ,"Elektronika inzenjering Galaksija"}, - {"hector", hector_cassette_formats ,"Micronique Hector & Interact Family Computer"}, - {"jupiter", ace_cassette_formats ,"Jupiter Cantab Jupiter Ace"}, - {"kc85", kc_cassette_formats ,"VEB Mikroelektronik KC 85"}, - {"kim1", kim1_cassette_formats ,"MOS KIM-1"}, - {"lviv", lviv_lvt_format ,"PK-01 Lviv"}, - {"mo5", mo5_cassette_formats ,"Thomson MO-series"}, - {"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"}, - {"primo", primo_ptp_format ,"Microkey Primo"}, - {"rku", rku_cassette_formats ,"UT-88"}, - {"rk8", rk8_cassette_formats ,"Mikro-80"}, - {"rks", rks_cassette_formats ,"Specialist"}, - {"rko", rko_cassette_formats ,"Orion"}, - {"rkr", rkr_cassette_formats ,"Radio-86RK"}, - {"rka", rka_cassette_formats ,"Zavod BRA Apogee BK-01"}, - {"rkm", rkm_cassette_formats ,"Mikrosha"}, - {"rkp", rkp_cassette_formats ,"SAM SKB VM Partner-01.01"}, - {"sc3000", sc3000_cassette_formats ,"Sega SC-3000"}, - {"sol20", sol20_cassette_formats ,"PTC SOL-20"}, - {"sorcerer", sorcerer_cassette_formats ,"Exidy Sorcerer"}, - {"sordm5", sordm5_cassette_formats ,"Sord M5"}, - {"spc1000", spc1000_cassette_formats ,"Samsung SPC-1000"}, - {"svi", svi_cassette_formats ,"Spectravideo SVI-318 & SVI-328"}, - {"to7", to7_cassette_formats ,"Thomson TO-series"}, - {"trs80l2", trs80l2_cassette_formats ,"TRS-80 Level 2"}, - {"tvc64", tvc64_cassette_formats ,"Videoton TVC 64"}, - {"tzx", tzx_cassette_formats ,"Sinclair ZX Spectrum"}, - {"vg5k", vg5k_cassette_formats ,"Philips VG 5000"}, - {"vtech1", vtech1_cassette_formats ,"Video Technology Laser 110-310"}, - {"vtech2", vtech2_cassette_formats ,"Video Technology Laser 350-700"}, - {"x07", x07_cassette_formats ,"Canon X-07"}, - {"x1", x1_cassette_formats ,"Sharp X1"}, - {"zx80_o", zx80_o_format ,"Sinclair ZX80"}, - {"zx81_p", zx81_p_format ,"Sinclair ZX81"}, - - - - {nullptr,nullptr,nullptr} -}; - - -static std::string get_extension(const char *name) -{ - const char *s; - s = name; - if (s != nullptr) - s = strrchr(s, '.'); - return s ? std::string(s+1) : ""; -} - -static void display_usage(const char *argv0) -{ - fprintf(stderr, "Usage: \n"); - fprintf(stderr, " %s convert \n", argv0); -} - -static void display_formats(void) -{ - int i,j; - fprintf(stderr, "Supported formats:\n\n"); - for (i = 0; formats[i].name; i++) { - fprintf(stderr, "%10s - %s\n",formats[i].name,formats[i].desc); - for (j = 1; formats[i].formats[j]; j++) { - fprintf(stderr, "%15s %s\n","",formats[i].formats[j]->extensions); - } - } -} - -int CLIB_DECL main(int argc, char *argv[]) -{ - int i; - int found =0; - const cassette_image::Format * const *selected_formats = nullptr; - cassette_image::ptr cassette; - - if (argc > 1) - { - if (!core_stricmp("convert", argv[1])) - { - // convert command - if (argc!=5) { - fprintf(stderr, "Wrong parameter number.\n\n"); - display_usage(argv[0]); - return -1; - } else { - for (i = 0; formats[i].name; i++) { - if (core_stricmp(formats[i].name,argv[2])==0) { - selected_formats = formats[i].formats; - found = 1; - } - } - if (found==0) { - fprintf(stderr, "Wrong format name.\n\n"); - display_usage(argv[0]); - fprintf(stderr, "\n"); - display_formats(); - return -1; - } - - FILE *f = fopen(argv[3], "rb"); - if (!f) { - fprintf(stderr, "File %s not found.\n",argv[3]); - return -1; - } - - 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"); - return -1; - } - - cassette->dump(argv[4]); - cassette.reset(); - goto theend; - } - } - } - - /* Usage */ - fprintf(stderr, "castool - Generic cassette manipulation tool for use with MAME\n\n"); - display_usage(argv[0]); - fprintf(stderr, "\n"); - display_formats(); - fprintf(stderr, "\nExample usage:\n"); - fprintf(stderr, " %s convert tzx game.tzx game.wav\n\n", argv[0]); - -theend : - return 0; -} diff --git a/src/tools/discrepancy-fixer.py b/src/tools/discrepancy-fixer.py deleted file mode 100755 index d36d286..0000000 --- a/src/tools/discrepancy-fixer.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/python -## -## license:BSD-3-Clause -## copyright-holders:Zoe Blade - -# Fix discrepancies in arcade ROM dump names, by Zoe Blade -# For Python 2 and 3 - -import sys -import xml.etree.ElementTree - - -def fixPair(parentMachine, childMachine): - changes = { } - for childRom in childMachine.iter('rom'): - for parentRom in parentMachine.iter('rom'): - if parentRom.get('sha1') == childRom.get('sha1'): - # ROM pair found - if parentRom.get('name') != childRom.get('name'): - # The names don't match - changes[childRom.get('name')] = parentRom.get('name') - - if changes: - sourceFilename = childMachine.get('sourcefile') - - try: - input = open(sourceFilename, 'r') - source = input.read() - input.close() - except Exception as e: - sys.stderr.write('%s: error reading %s: %s\n' % (sys.argv[0], sourceFilename, e)) - return False - - for oldRomFilename in changes: - newRomFilename = '"%s"' % (changes[oldRomFilename]) - oldRomFilename = '"%s"' % (oldRomFilename) - - paddedLen = max(len(oldRomFilename), len(newRomFilename)) - oldRomFilenamePadded = oldRomFilename.ljust(paddedLen, ' ') - newRomFilenamePadded = newRomFilename.ljust(paddedLen, ' ') - - source = source.replace(oldRomFilenamePadded, newRomFilenamePadded) # Try to preserve fancy spacing where possible - source = source.replace(oldRomFilename, newRomFilename) # Fallback on just replacing the filename - - sys.stdout.write('%s: %s -> %s\n' % (sourceFilename, oldRomFilename, newRomFilename)) - - output = open(sourceFilename, 'w') - output.write(source) - output.close() - - return True - - -if __name__ == '__main__': - if len(sys.argv) > 2: - sys.stderr.write('Usage:\n%s [arcade.xml]\n' % sys.argv[0]) - sys.exit(1) - - if len(sys.argv) > 1: - filename = sys.argv[1] - else: - filename = 'arcade.xml' - - sys.stderr.write('Loading XML file...') - sys.stderr.flush() - try: - root = xml.etree.ElementTree.parse(filename).getroot() - except Exception as e: - sys.stderr.write('\n%s: error parsing %s: %s\n' % (sys.argv[0], filename, e)) - sys.exit(2) - sys.stderr.write('done.\n') - - errors = 0 - for childMachine in root.iter('machine'): - if childMachine.get('cloneof'): - for parentMachine in root.iter('machine'): - if parentMachine.get('name') == childMachine.get('cloneof'): - # Machine pair found - if not fixPair(parentMachine, childMachine): - errors += 1 - - sys.exit(0 if errors == 0 else 3) diff --git a/src/tools/discrepancy-spotter.py b/src/tools/discrepancy-spotter.py deleted file mode 100755 index 27ba7c0..0000000 --- a/src/tools/discrepancy-spotter.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/python -## -## license:BSD-3-Clause -## copyright-holders:Zoe Blade - -# Find discrepancies in arcade ROM dump names, by Zoe Blade -# For Python 2 and 3 - -import sys -import xml.etree.ElementTree - - -def checkPair(parentMachine, childMachine): - for childRom in childMachine.iter('rom'): - for parentRom in parentMachine.iter('rom'): - if parentRom.get('sha1') == childRom.get('sha1'): - # ROM pair found - if parentRom.get('name') != childRom.get('name'): - # The names don't match - sys.stdout.write('%s %s: %s -> %s\n' % (childMachine.get('sourcefile'), childMachine.get('name'), childRom.get('name'), parentRom.get('name'))) - else: - break - - -if __name__ == '__main__': - if len(sys.argv) > 2: - sys.stderr.write('Usage:\n%s [arcade.xml]\n' % sys.argv[0]) - sys.exit(1) - - if len(sys.argv) > 1: - filename = sys.argv[1] - else: - filename = 'arcade.xml' - - sys.stderr.write('Loading XML file...') - sys.stderr.flush() - try: - root = xml.etree.ElementTree.parse(filename).getroot() - except Exception as e: - sys.stderr.write('\n%s: error parsing %s: %s\n' % (sys.argv[0], filename, e)) - sys.exit(2) - sys.stderr.write('done.\n') - - for childMachine in root.iter('machine'): - if childMachine.get('cloneof'): - for parentMachine in root.iter('machine'): - if parentMachine.get('name') == childMachine.get('cloneof'): - # Machine pair found - checkPair(parentMachine, childMachine) - - sys.exit(0) diff --git a/src/tools/floptool.cpp b/src/tools/floptool.cpp deleted file mode 100644 index f021e08..0000000 --- a/src/tools/floptool.cpp +++ /dev/null @@ -1,711 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Olivier Galibert -/*************************************************************************** - - (Floppy) image command-line manager - -***************************************************************************/ - -#include "image_handler.h" - -#include "corestr.h" -#include "ioprocs.h" - -#include -#include -#include -#include -#include -#include -#include - - -static formats_table formats; - -static void display_usage() -{ - fprintf(stderr, "Usage: \n"); - fprintf(stderr, " floptool.exe identify [ ...] -- Identify an image format\n"); - fprintf(stderr, " floptool.exe flopconvert [input_format|auto] output_format -- Convert a floppy image\n"); - fprintf(stderr, " floptool.exe flopcreate output_format filesystem -- Create a preformatted floppy image\n"); - fprintf(stderr, " floptool.exe flopdir input_format filesystem -- List the contents of a floppy image\n"); - fprintf(stderr, " floptool.exe flopread input_format filesystem -- Extract a file from a floppy image\n"); - fprintf(stderr, " floptool.exe flopwrite input_format filesystem -- Write a file into a floppy image\n"); -} - -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; - } - - for(const auto &e : formats.filesystem_format_by_key) { - int sz = e.first.size(); - if(sz > sk) - sk = sz; - } - - for(const auto &e : formats.floppy_create_info_by_key) { - int sz = e.first.size(); - if(sz > sk) - sk = sz; - } - - 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()); - } - - 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); - } - } -} - -static void display_full_usage() -{ - /* Usage */ - fprintf(stderr, "floptool - Generic floppy image manipulation tool for use with MAME\n\n"); - display_usage(); - fprintf(stderr, "\n"); - display_formats(); - -} - -static int identify(int argc, char *argv[]) -{ - // Need to detect CHDs too - - if(argc<3) { - fprintf(stderr, "Missing name of file to identify.\n\n"); - display_usage(); - return 1; - } - - int sz = 0; - for(int i=2; i sz) - sz = len; - } - - for(int i=2; im_format->name()); - if(len > sz2) - sz2 = len; - } - - bool first = true; - for(const auto &e : scores) { - printf("%-*s %c %3d - %-*s %s\n", sz, first ? argv[i] : "", first ? ':' : ' ', e.first, 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; - - } else { - source_format = formats.find_floppy_format_info_by_key(name); - if(!source_format) { - fprintf(stderr, "Error: Format '%s' unknown\n", name); - return nullptr; - - } - } - return source_format; -} - -static int flopconvert(int argc, char *argv[]) -{ - if(argc!=6) { - fprintf(stderr, "Incorrect number of arguments.\n\n"); - display_usage(); - 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; - - 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: Aaving to format '%s' unsupported\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; - } - - ih.set_on_disk_path(argv[5]); - - if(ih.floppy_save(dest_format)) { - fprintf(stderr, "Error: Saving as format '%s' failed\n", dest_format->m_format->name()); - return 1; - } - - return 0; -} - -static int flopcreate(int argc, char *argv[]) -{ - if(argc!=5) { - fprintf(stderr, "Incorrect number of arguments.\n\n"); - display_usage(); - 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[3]); - return 1; - } - if(!dest_format->m_format->supports_save()) { - fprintf(stderr, "Error: Saving to format '%s' unsupported\n", argv[3]); - 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->can_format()) { - fprintf(stderr, "Error: Floppy creation format '%s' does not support creating new images\n", argv[3]); - return 1; - } - - fs_meta_data meta; - image_handler ih; - ih.set_on_disk_path(argv[4]); - - ih.floppy_create(create_fs, meta); - return ih.floppy_save(dest_format); -} - -static void dir_scan(u32 depth, filesystem_t::dir_t dir, std::vector> &entries, const std::unordered_map &nmap, size_t nc, const std::vector &dmetad, const std::vector &fmetad) -{ - std::string head; - for(u32 i = 0; i != depth; i++) - head += " "; - auto contents = dir.contents(); - 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: { - auto subdir = dir.dir_get(c.m_key); - auto meta = subdir.metadata(); - for(const auto &m : dmetad) { - if(!meta.has(m.m_name)) - continue; - size_t slot = nmap.find(m.m_name)->second; - std::string val = fs_meta::to_string(m.m_type, meta.get(m.m_name)); - if(slot == 0) - val = head + "dir " + val; - entries[id][slot] = val; - } - dir_scan(depth+1, subdir, entries, nmap, nc, dmetad, fmetad); - break; - } - case fs_dir_entry_type::file: - case fs_dir_entry_type::system_file: { - auto file = dir.file_get(c.m_key); - auto meta = file.metadata(); - for(const auto &m : fmetad) { - if(!meta.has(m.m_name)) - continue; - size_t slot = nmap.find(m.m_name)->second; - std::string val = fs_meta::to_string(m.m_type, meta.get(m.m_name)); - if(slot == 0) - val = head + (c.m_type == fs_dir_entry_type::system_file ? "sys " : "file ") + val; - entries[id][slot] = val; - } - break; - } - } - } -} - -static int generic_dir(image_handler &ih) -{ - 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->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), fs_meta::to_string(e.m_type, vmeta.get(e.m_name))); - printf("%s\n\n", vinf.c_str()); - } - - std::vector 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 nmap; - for(size_t i = 0; i != names.size(); i++) - nmap[names[i]] = i; - - auto root = fs->root(); - std::vector> entries; - - entries.resize(1); - for(fs_meta_name n : names) - entries[0].push_back(fs_meta_data::entry_name(n)); - - dir_scan(0, root, entries, nmap, names.size(), dmetad, fmetad); - - std::vector sizes(names.size()); - - for(const auto &e : entries) - for(unsigned int i=0; i != names.size(); i++) - sizes[i] = std::max(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 0; -} - -static int flopdir(int argc, char *argv[]) -{ - if(argc!=5) { - fprintf(stderr, "Incorrect number of arguments.\n\n"); - display_usage(); - 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 int hddir(int argc, char *argv[]) -{ - if(argc!=4) { - fprintf(stderr, "Incorrect number of arguments.\n\n"); - display_usage(); - 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 int generic_read(image_handler &ih, const char *srcpath, const char *dstpath) -{ - auto [fsm, fs] = ih.get_fs(); - - std::vector path = ih.path_split(srcpath); - - auto dir = fs->root(); - std::string apath; - for(unsigned int i = 0; i < path.size() - 1; i++) { - auto c = dir.contents(); - unsigned int j; - for(j = 0; j != c.size(); j++) - if(c[j].m_name == path[i]) - break; - if(j == c.size()) { - fprintf(stderr, "Error: directory %s%c%s not found\n", apath.c_str(), fsm->directory_separator(), path[i].c_str()); - return 1; - } - if(c[j].m_type != fs_dir_entry_type::dir) { - fprintf(stderr, "Error: %s%c%s is not a directory\n", apath.c_str(), fsm->directory_separator(), path[i].c_str()); - return 1; - } - dir = dir.dir_get(c[j].m_key); - apath += fsm->directory_separator() + path[i]; - } - - auto c = dir.contents(); - unsigned int j; - for(j = 0; j != c.size(); j++) - if(c[j].m_name == path.back()) - break; - if(j == c.size()) { - fprintf(stderr, "Error: file %s%c%s not found\n", apath.c_str(), fsm->directory_separator(), path.back().c_str()); - return 1; - } - auto file = dir.file_get(c[j].m_key); - auto meta = file.metadata(); - - if(!meta.has(fs_meta_name::length)) { - fprintf(stderr, "Error: %s%c%s is not a readable file\n", apath.c_str(), fsm->directory_separator(), path.back().c_str()); - return 1; - } - - image_handler::fsave(dstpath, file.read_all()); - - bool has_rsrc = fsm->has_rsrc() && meta.has(fs_meta_name::rsrc_length); - - if(has_rsrc) - image_handler::fsave_rsrc(image_handler::path_make_rsrc(dstpath), file.rsrc_read_all()); - - return 0; -} - - -static int flopread(int argc, char *argv[]) -{ - if(argc!=7) { - fprintf(stderr, "Incorrect number of arguments.\n\n"); - display_usage(); - 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_read(ih, argv[5], argv[6]); -} - -static int hdread(int argc, char *argv[]) -{ - if(argc!=6) { - fprintf(stderr, "Incorrect number of arguments.\n\n"); - display_usage(); - 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_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 path = ih.path_split(dstpath); - - auto dir = fs->root(); - std::string apath; - for(unsigned int i = 0; i < path.size() - 1; i++) { - auto c = dir.contents(); - unsigned int j; - for(j = 0; j != c.size(); j++) - if(c[j].m_name == path[i]) - break; - if(j == c.size()) { - fprintf(stderr, "Error: directory %s%c%s not found\n", apath.c_str(), fsm->directory_separator(), path[i].c_str()); - return 1; - } - if(c[j].m_type != fs_dir_entry_type::dir) { - fprintf(stderr, "Error: %s%c%s is not a directory\n", apath.c_str(), fsm->directory_separator(), path[i].c_str()); - return 1; - } - dir = dir.dir_get(c[j].m_key); - apath += fsm->directory_separator() + path[i]; - } - - - fs_meta_data meta; - meta.set(fs_meta_name::name, path.back()); - - auto file = dir.file_create(meta); - auto filedata = image_handler::fload(srcpath); - file.replace(filedata); - - bool has_rsrc = fsm->has_rsrc(); - - if(has_rsrc) { - std::string rpath = image_handler::path_make_rsrc(dstpath); - - if(image_handler::fexists(rpath)) { - filedata = image_handler::fload_rsrc(rpath); - if(!filedata.empty()) - file.rsrc_replace(filedata); - } - } - - return 0; -} - - -static int flopwrite(int argc, char *argv[]) -{ - if(argc!=7) { - fprintf(stderr, "Incorrect number of arguments.\n\n"); - display_usage(); - 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; - } - - 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(); - 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_write(ih, argv[4], argv[5]); -} - -int CLIB_DECL main(int argc, char *argv[]) -{ - formats.init(); - - if(argc == 1) { - display_full_usage(); - return 0; - } - - 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 { - fprintf(stderr, "Unknown command '%s'\n\n", argv[1]); - display_usage(); - return 1; - } - } catch(const emu_fatalerror &err) { - fprintf(stderr, "Error: %s", err.what()); - return 1; - } -} diff --git a/src/tools/image_handler.cpp b/src/tools/image_handler.cpp deleted file mode 100644 index a520383..0000000 --- a/src/tools/image_handler.cpp +++ /dev/null @@ -1,409 +0,0 @@ -// 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" - - -// Fatalerror implementation - -emu_fatalerror::emu_fatalerror(util::format_argument_pack const &args) - : emu_fatalerror(0, args) -{ -} - -emu_fatalerror::emu_fatalerror(int _exitcode, util::format_argument_pack const &args) - : m_text(util::string_format(args)) - , m_code(_exitcode) -{ -} - - -// 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(floppy_format_type format) { - m_table->floppy_format_infos.emplace_back(std::make_unique(format(), m_category)); - } - - virtual void add(const filesystem_manager_t &fs) { - m_table->filesystem_formats.emplace_back(std::make_unique(&fs, m_category)); - } - }; - - struct fs_enum : public filesystem_manager_t::floppy_enumerator { - filesystem_format *m_format; - - fs_enum(filesystem_format *format) : m_format(format) {} - - virtual void add(floppy_format_type 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(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(name, key, description)); - } - }; -} - -void formats_table::init() -{ - std::vector variants; - - enumerator en(this); - mame_formats_full_list(en); - - for(auto &f : filesystem_formats) { - fs_enum fen(f.get()); - f->m_manager->enumerate_f(fen, floppy_image::FF_UNKNOWN, variants); - } - - 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 image_handler::fload(std::string path) -{ - char msg[4096]; - sprintf(msg, "Error opening %s for reading", path.c_str()); - auto fi = fopen(path.c_str(), "rb"); - if(!fi) { - perror(msg); - exit(1); - } - fseek(fi, 0, SEEK_END); - long size = ftell(fi); - std::vector filedata(size); - fseek(fi, 0, SEEK_SET); - fread(filedata.data(), filedata.size(), 1, fi); - fclose(fi); - - return filedata; -} - -std::vector image_handler::fload_rsrc(std::string path) -{ - auto filedata = fload(path); - const u8 *head = filedata.data(); - - if(filesystem_t::r32b(head+0x00) == 0x00051607 && - filesystem_t::r32b(head+0x04) == 0x00020000) { - u16 nent = filesystem_t::r16b(head+0x18); - for(u16 i=0; i != nent; i++) { - const u8 *e = head + 12*i; - if(filesystem_t::r32b(e+0) == 2) { - u32 start = filesystem_t::r32b(e+4); - u32 len = filesystem_t::r32b(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 &data) -{ - char msg[4096]; - sprintf(msg, "Error opening %s for writing", path.c_str()); - auto fo = fopen(path.c_str(), "wb"); - if(!fo) { - perror(msg); - exit(1); - } - - fwrite(data.data(), data.size(), 1, fo); - fclose(fo); -} - -void image_handler::fsave_rsrc(std::string path, const std::vector &data) -{ - u8 head[0x2a]; - - filesystem_t::w32b(head+0x00, 0x00051607); // Magic - filesystem_t::w32b(head+0x04, 0x00020000); // Version - filesystem_t::fill(head+0x08, 0, 16); // Filler - filesystem_t::w16b(head+0x18, 1); // Number of entries - filesystem_t::w32b(head+0x1a, 2); // Resource fork - filesystem_t::w32b(head+0x22, 0x2a); // Offset in the file - filesystem_t::w32b(head+0x26, data.size()); // Length - - char msg[4096]; - sprintf(msg, "Error opening %s for writing", path.c_str()); - auto fo = fopen(path.c_str(), "wb"); - if(!fo) { - perror(msg); - 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> image_handler::identify(const formats_table &formats) -{ - std::vector> res; - std::vector 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) - res.emplace_back(std::make_pair(score, e.second)); - } - - return res; -} - -bool image_handler::floppy_load(const floppy_format_info *format) -{ - std::vector 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) -{ - std::vector variants; - std::string msg = util::string_format("Error opening %s for writing", m_on_disk_path); - FILE *f = fopen(m_on_disk_path.c_str(), "wb"); - if (!f) { - 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 variants; - std::vector img(format->m_image_size); - fsblk_vec_t blockdev(img); - auto fs = format->m_manager->mount(blockdev); - fs->format(meta); - - auto source_format = format->m_type(); - auto io = util::ram_read(img.data(), img.size(), 0xff); - source_format->load(*io, floppy_image::FF_UNKNOWN, variants, &m_floppy_image); - delete source_format; - } else { - fs_unformatted::format(format->m_key, &m_floppy_image); - } -} - -bool image_handler::floppy_mount_fs(const filesystem_format *format) -{ - m_floppy_fs_converter = nullptr; - for(const auto &ci : format->m_floppy_create) { - if(ci->m_type != m_floppy_fs_converter) { - std::vector variants; - m_floppy_fs_converter = ci->m_type; - m_sector_image.clear(); - auto load_format = m_floppy_fs_converter(); - util::random_read_write_fill_wrapper, 0xff> io(m_sector_image); - load_format->save(io, variants, &m_floppy_image); - delete load_format; - } - - 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 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 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 variants; - auto io = util::ram_read(m_sector_image.data(), m_sector_image.size(), 0xff); - auto format = m_floppy_fs_converter(); - format->load(*io, floppy_image::FF_UNKNOWN, variants, &m_floppy_image); - delete format; -} - -std::vector image_handler::path_split(std::string path) const -{ - std::string opath = path; - std::vector 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 deleted file mode 100644 index d9a861b..0000000 --- a/src/tools/image_handler.h +++ /dev/null @@ -1,119 +0,0 @@ -// 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 "../emu/emucore.h" - -#include "formats/fsmgr.h" - -#include -#include -#include -#include -#include - - -using u8 = uint8_t; -using u16 = uint16_t; -using u32 = uint32_t; - -struct floppy_format_info { - floppy_image_format_t *m_format; - std::string m_category; - - floppy_format_info(floppy_image_format_t *format, std::string category) : m_format(format), m_category(category) {} -}; - -struct floppy_create_info { - const filesystem_manager_t *m_manager; - - floppy_format_type m_type; - u32 m_image_size; - u32 m_key; - const char *m_name; - const char *m_description; - - floppy_create_info(const filesystem_manager_t *manager, floppy_format_type 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 filesystem_manager_t *m_manager; - std::vector> m_floppy_create; - std::string m_category; - bool m_floppy, m_floppy_raw, m_hd, m_cd; - - filesystem_format(const filesystem_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> floppy_format_infos; - std::vector> filesystem_formats; - - std::map floppy_format_info_by_key; - std::map filesystem_format_by_key; - std::map floppy_create_info_by_key; - - std::map> floppy_format_info_by_category; - std::map> 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> identify(const formats_table &formats); - - bool floppy_load(const floppy_format_info *format); - bool floppy_save(const floppy_format_info *format); - - 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 get_fs() const { return std::make_pair(m_fsm, m_fs.get()); } - - std::vector path_split(std::string path) const; - - static std::vector fload(std::string path); - static std::vector fload_rsrc(std::string path); - static void fsave(std::string path, const std::vector &data); - static void fsave_rsrc(std::string path, const std::vector &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; - - floppy_format_type m_floppy_fs_converter; - std::vector m_sector_image; - std::unique_ptr m_fsblk; - const filesystem_manager_t *m_fsm; - std::unique_ptr m_fs; - -}; - -#endif // MAME_TOOLS_IMAGE_HANDLER_H diff --git a/src/tools/imgtool/charconv.cpp b/src/tools/imgtool/charconv.cpp deleted file mode 100644 index 3ff6de6..0000000 --- a/src/tools/imgtool/charconv.cpp +++ /dev/null @@ -1,107 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/*************************************************************************** - - charconv.cpp - - Imgtool character set conversion routines. - -***************************************************************************/ - -#include "charconv.h" - -#include "corestr.h" - -#include - -imgtool::simple_charconverter imgtool::charconverter_iso_8859_1(nullptr, nullptr); - - -//------------------------------------------------- -// simple_charconverter::simple_charconverter -//------------------------------------------------- - -imgtool::simple_charconverter::simple_charconverter(const char32_t lowpage[0x80], const char32_t highpage[0x80], unicode_normalization_form norm) - : m_norm(norm), m_lowpage(lowpage), m_highpage(highpage) -{ - // build the reverse lookup table - for (int i = 0; i < 256; i++) - { - const char32_t *page = i >= 128 ? m_highpage : m_lowpage; - char32_t unicode_char = page ? page[i % 128] : i; - m_reverse_lookup.emplace_back(unicode_char, (char)i); - } - - // and sort it - std::sort(m_reverse_lookup.begin(), m_reverse_lookup.end(), [](const std::pair &a, const std::pair &b) - { - return b.first > a.first; - }); -} - - -//------------------------------------------------- -// from_utf8 -//------------------------------------------------- - -void imgtool::simple_charconverter::from_utf8(std::ostream &dest, std::string_view src) const -{ - // normalize the incoming unicode - std::string const normalized_src = normalize_unicode(src, m_norm); - - auto nsrc = std::string_view(normalized_src); - while (!nsrc.empty()) - { - // get the next character - char32_t ch; - int rc = uchar_from_utf8(&ch, nsrc); - if (rc < 0) - { - ch = 0xFFFD; - rc = 1; - } - 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 &a, const char32_t &b) - { - return a.first < b; - }); - if (lookup == m_reverse_lookup.end()) - throw charconverter_exception(); - - // and output the results - dest << lookup->second; - } -} - - -//------------------------------------------------- -// to_utf8 -//------------------------------------------------- - -void imgtool::simple_charconverter::to_utf8(std::ostream &dest, std::string_view src) const -{ - for (uint8_t c : src) - { - // which page is this in? - const char32_t *page = ((c & 0x80) == 0) ? m_lowpage : m_highpage; - - // is this page present? - if ((c & 0x80) == 0) - { - // no - pass it on - dest << c; - } - else - { - // yes - we need to do a lookup - size_t base = ((c & 0x80) == 0) ? 0x00 : 0x80; - char32_t ch = page[((unsigned char)(c)) - base]; - if (ch == 0) - throw charconverter_exception(); - - dest << utf8_from_uchar(ch); - } - } -} diff --git a/src/tools/imgtool/charconv.h b/src/tools/imgtool/charconv.h deleted file mode 100644 index 7df16f8..0000000 --- a/src/tools/imgtool/charconv.h +++ /dev/null @@ -1,82 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/*************************************************************************** - - charconv.h - - Imgtool character set conversion routines. - -***************************************************************************/ - - -#ifndef IMGTOOL_CHARCONV_H -#define IMGTOOL_CHARCONV_H - -#include "unicode.h" - -#include -#include -#include - -namespace imgtool -{ - // ======================> charconverter - - // abstract base class for character conversions - class charconverter - { - public: - 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 - { - // inlining so that the return value can potentially be removed by return value optimization - std::ostringstream stream; - from_utf8(stream, src); - return stream.str(); - } - - std::string to_utf8(const std::string &src) const - { - // inlining so that the return value can potentially be removed by return value optimization - std::ostringstream stream; - to_utf8(stream, src); - return stream.str(); - } - - }; - - // ======================> simple_charconverter - - // a simple implementation of charconverter that simply defines a code page for 0x80-0xFF - class simple_charconverter : public charconverter - { - public: - simple_charconverter(const char32_t highpage[0x80], unicode_normalization_form norm = unicode_normalization_form::C) - : simple_charconverter(nullptr, highpage, norm) - { - } - - 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, std::string_view src) const override; - virtual void to_utf8(std::ostream &dest, std::string_view src) const override; - - private: - std::vector > m_reverse_lookup; - unicode_normalization_form m_norm; - const char32_t *m_lowpage; - const char32_t *m_highpage; - }; - - // exception that can be thrown from charconverter::from_utf8() if a character is illegal (charconverter::to_utf8() should never throw this) - class charconverter_exception - { - }; - - extern simple_charconverter charconverter_iso_8859_1; -}; - - -#endif // IMGTOOL_CHARCONV_H diff --git a/src/tools/imgtool/filtbas.cpp b/src/tools/imgtool/filtbas.cpp deleted file mode 100644 index acd11a7..0000000 --- a/src/tools/imgtool/filtbas.cpp +++ /dev/null @@ -1,3123 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/**************************************************************************** - - filtbas.c - - Filter for Microsoft-style tokenized BASIC files - - BASIC files typically follow the following format: - - int8 $ff - int16 - ... - int16 - int16 - int8[] - int8 $00 End of line delimiter - -*****************************************************************************/ - -#include -#include -#include - -#include "imgtool.h" -#include "filter.h" - -#include "formats/imageutl.h" - - -/*************************************************************************** - CONSTANTS -***************************************************************************/ - -#define EOLN (CRLF == 1 ? "\r" : (CRLF == 2 ? "\n" : (CRLF == 3 ? "\r\n" : NULL))) - - - -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ - -struct basictoken_tableent -{ - uint8_t shift; - uint8_t base; - const char *const *tokens; - int num_tokens; -}; - - - -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; -}; - - - -/*************************************************************************** - IMPLEMENTATION -***************************************************************************/ - -/*------------------------------------------------- - basic_readfile - reads a file and decodes - BASIC tokens into ASCII text --------------------------------------------------*/ - -static imgtoolerr_t basic_readfile(const basictokens *tokens, - imgtool::partition &partition, const char *filename, - const char *fork, imgtool::stream &destf) -{ - imgtoolerr_t err; - imgtool::stream::ptr mem_stream; - uint8_t line_header[4]; - uint16_t line_number; //, address; - uint8_t b, shift; - int i; - int in_string = false; - const basictoken_tableent *token_table; - const char *token; - - /* open a memory stream */ - mem_stream = imgtool::stream::open_mem(nullptr, 0); - if (!mem_stream) - return IMGTOOLERR_OUTOFMEMORY; - - /* read actual file */ - err = partition.read_file(filename, fork, *mem_stream, nullptr); - if (err) - return err; - - /* skip first few bytes */ - mem_stream->seek(tokens->skip_bytes, SEEK_SET); - - /* keep reading line headers */ - while(mem_stream->read(line_header, sizeof(line_header)) == sizeof(line_header)) - { - /* 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); - } - else - { - //address = (uint16_t) - pick_integer_le(line_header, 0, 2); - line_number = (uint16_t) pick_integer_le(line_header, 2, 2); - } - - /* write the line number */ - destf.printf("%u ", (unsigned) line_number); - shift = 0x00; - - in_string = false; // in case the last line didn't terminate a string - - while((mem_stream->read(&b, 1) > 0) && (b != 0x00)) - { - if (b == 0x22) - in_string = in_string ? false : true; - - if ((b & 0x80) && (!in_string)) - { - token = nullptr; - - for (i = 0; i < tokens->num_entries; i++) - { - token_table = &tokens->entries[i]; - if (token_table->shift == shift) - { - if ((b - 0x80) < token_table->num_tokens) - { - token = token_table->tokens[b - 0x80]; - if (token) - shift = 0x00; - } - } - - if (token_table->shift == b) - { - shift = token_table->shift; - break; - } - } - - if (shift == 0x00) - destf.puts(token ? token : "!"); - } - else - { - destf.putc((char) b); - } - } - - destf.puts(EOLN); - } - - return err; -} - - - -/*------------------------------------------------- - basic_writefile - translates ASCII text to - BASIC tokens and writes it to a file --------------------------------------------------*/ - -static imgtoolerr_t basic_writefile(const basictokens *tokens, - imgtool::partition &partition, const char *filename, - const char *fork, imgtool::stream &sourcef, util::option_resolution *opts) -{ - imgtool::stream::ptr mem_stream; - char buf[1024]; - int eof = false; - uint32_t len; - char c; - int i, j, pos, in_quotes; - uint16_t line_number; - uint8_t line_header[4]; - uint8_t file_size[2]; - const basictoken_tableent *token_table; - const char *token; - uint8_t token_shift, token_value; - uint16_t address; - - /* open a memory stream */ - mem_stream = imgtool::stream::open_mem(nullptr, 0); - if (!mem_stream) - return IMGTOOLERR_OUTOFMEMORY; - - /* write header */ - mem_stream->write(tokens->bytes, tokens->skip_bytes); - /* loop until the file is complete */ - while(!eof) - { - /* read a line */ - pos = 0; - while((len = sourcef.read(&c, 1)) > 0) - { - /* break if at end of line */ - if ((c == '\r') || (c == '\n')) - break; - - if (pos <= std::size(buf) - 1) - { - buf[pos++] = c; - } - } - eof = (len == 0); - buf[pos] = '\0'; - - /* ignore lines that don't start with digits */ - if (isdigit(buf[0])) - { - /* start at beginning of line */ - pos = 0; - - /* read line number */ - line_number = 0; - while(isdigit(buf[pos])) - { - line_number *= 10; - line_number += (buf[pos++] - '0'); - } - - /* determine address */ - if (tokens->baseaddress != 0) - { - address = tokens->baseaddress + (uint16_t)mem_stream->size() + 4; - } - else - { - address = 0x0000; - } - - /* set up line header */ - 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); - } - else - { - place_integer_le(line_header, 0, 2, address); - place_integer_le(line_header, 2, 2, line_number); - } - - /* emit line header */ - mem_stream->write(line_header, sizeof(line_header)); - - /* skip spaces */ - while(isspace(buf[pos])) - pos++; - - /* when we start out, we are not within quotation marks */ - in_quotes = false; - - /* read until end of line */ - while(buf[pos] != '\0') - { - token = nullptr; - token_shift = 0; - token_value = 0; - - if (buf[pos] == '\"') - { - /* flip quotation status */ - in_quotes = !in_quotes; - } - else if (!in_quotes) - { - for (i = 0; (token == nullptr) && (i < tokens->num_entries); i++) - { - bool found = false; - token_table = &tokens->entries[i]; - for (j = 0; (token == nullptr) && (j < token_table->num_tokens); j++) - { - if (!strncmp(&buf[pos], token_table->tokens[j], strlen(token_table->tokens[j]))) - { - token = token_table->tokens[j]; - token_shift = token_table->shift; - token_value = token_table->base + j; - pos += strlen(token); - found = true; - break; - } - } - if (found) - break; - } - } - - /* did we find a token? */ - if (token != nullptr) - { - /* emit the token */ - if (token_shift != 0) - mem_stream->write(&token_shift, 1); - mem_stream->write(&token_value, 1); - } - else - { - /* no token; emit the byte */ - mem_stream->write(&buf[pos++], 1); - } - } - - /* emit line terminator */ - mem_stream->fill(0x00, 1); - } - } - - /* emit program terminator */ - mem_stream->fill(0x00, 2); - - /* reset stream */ - mem_stream->seek(tokens->size_pos, SEEK_SET); - - /* this is somewhat gross */ - if (tokens->skip_bytes >= 3) - { - if (tokens->be) - { - place_integer_be(file_size, 0, 2, mem_stream->size()); - } - else - { - place_integer_le(file_size, 0, 2, mem_stream->size()); - } - mem_stream->write(file_size, 2); - mem_stream->seek(0, SEEK_SET); - } - - /* write actual file */ - return partition.write_file(filename, fork, *mem_stream, opts, nullptr); -} - - - -/*************************************************************************** - TOKEN DEFINITIONS -***************************************************************************/ - -static const char *const cocobas_statements[] = -{ - "FOR", /* 0x80 */ - "GO", /* 0x81 */ - "REM", /* 0x82 */ - "'", /* 0x83 */ - "ELSE", /* 0x84 */ - "IF", /* 0x85 */ - "DATA", /* 0x86 */ - "PRINT", /* 0x87 */ - "ON", /* 0x88 */ - "INPUT", /* 0x89 */ - "END", /* 0x8a */ - "NEXT", /* 0x8b */ - "DIM", /* 0x8c */ - "READ", /* 0x8d */ - "RUN", /* 0x8e */ - "RESTORE", /* 0x8f */ - "RETURN", /* 0x90 */ - "STOP", /* 0x91 */ - "POKE", /* 0x92 */ - "CONT", /* 0x93 */ - "LIST", /* 0x94 */ - "CLEAR", /* 0x95 */ - "NEW", /* 0x96 */ - "CLOAD", /* 0x97 */ - "CSAVE", /* 0x98 */ - "OPEN", /* 0x99 */ - "CLOSE", /* 0x9a */ - "LLIST", /* 0x9b */ - "SET", /* 0x9c */ - "RESET", /* 0x9d */ - "CLS", /* 0x9e */ - "MOTOR", /* 0x9f */ - "SOUND", /* 0xa0 */ - "AUDIO", /* 0xa1 */ - "EXEC", /* 0xa2 */ - "SKIPF", /* 0xa3 */ - "TAB(", /* 0xa4 */ - "TO", /* 0xa5 */ - "SUB", /* 0xa6 */ - "THEN", /* 0xa7 */ - "NOT", /* 0xa8 */ - "STEP", /* 0xa9 */ - "OFF", /* 0xaa */ - "+", /* 0xab */ - "-", /* 0xac */ - "*", /* 0xad */ - "/", /* 0xae */ - "^", /* 0xaf */ - "AND", /* 0xb0 */ - "OR", /* 0xb1 */ - ">", /* 0xb2 */ - "=", /* 0xb3 */ - "<", /* 0xb4 */ - "DEL", /* 0xb5 */ - "EDIT", /* 0xb6 */ - "TRON", /* 0xb7 */ - "TROFF", /* 0xb8 */ - "DEF", /* 0xb9 */ - "LET", /* 0xba */ - "LINE", /* 0xbb */ - "PCLS", /* 0xbc */ - "PSET", /* 0xbd */ - "PRESET", /* 0xbe */ - "SCREEN", /* 0xbf */ - "PCLEAR", /* 0xc0 */ - "COLOR", /* 0xc1 */ - "CIRCLE", /* 0xc2 */ - "PAINT", /* 0xc3 */ - "GET", /* 0xc4 */ - "PUT", /* 0xc5 */ - "DRAW", /* 0xc6 */ - "PCOPY", /* 0xc7 */ - "PMODE", /* 0xc8 */ - "PLAY", /* 0xc9 */ - "DLOAD", /* 0xca */ - "RENUM", /* 0xcb */ - "FN", /* 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 */ - "DOS", /* 0xe1 */ - "WIDTH", /* 0xe2 */ - "PALETTE", /* 0xe3 */ - "HSCREEN", /* 0xe4 */ - "LPOKE", /* 0xe5 */ - "HCLS", /* 0xe6 */ - "HCOLOR", /* 0xe7 */ - "HPAINT", /* 0xe8 */ - "HCIRCLE", /* 0xe9 */ - "HLINE", /* 0xea */ - "HGET", /* 0xeb */ - "HPUT", /* 0xec */ - "HBUFF", /* 0xed */ - "HPRINT", /* 0xee */ - "ERR", /* 0xef */ - "BRK", /* 0xf0 */ - "LOCATE", /* 0xf1 */ - "HSTAT", /* 0xf2 */ - "HSET", /* 0xf3 */ - "HRESET", /* 0xf4 */ - "HDRAW", /* 0xf5 */ - "CMP", /* 0xf6 */ - "RGB", /* 0xf7 */ - "ATTR" /* 0xf8 */ -}; - -static const char *const cocobas_functions[] = -{ - "SGN", /* 0xff80 */ - "INT", /* 0xff81 */ - "ABS", /* 0xff82 */ - "USR", /* 0xff83 */ - "RND", /* 0xff84 */ - "SIN", /* 0xff85 */ - "PEEK", /* 0xff86 */ - "LEN", /* 0xff87 */ - "STR$", /* 0xff88 */ - "VAL", /* 0xff89 */ - "ASC", /* 0xff8a */ - "CHR$", /* 0xff8b */ - "EOF", /* 0xff8c */ - "JOYSTK", /* 0xff8d */ - "LEFT$", /* 0xff8e */ - "RIGHT$", /* 0xff8f */ - "MID$", /* 0xff90 */ - "POINT", /* 0xff91 */ - "INKEY$", /* 0xff92 */ - "MEM", /* 0xff93 */ - "ATN", /* 0xff94 */ - "COS", /* 0xff95 */ - "TAN", /* 0xff96 */ - "EXP", /* 0xff97 */ - "FIX", /* 0xff98 */ - "LOG", /* 0xff99 */ - "POS", /* 0xff9a */ - "SQR", /* 0xff9b */ - "HEX$", /* 0xff9c */ - "VARPTR", /* 0xff9d */ - "INSTR", /* 0xff9e */ - "TIMER", /* 0xff9f */ - "PPOINT", /* 0xffa0 */ - "STRING$", /* 0xffa1 */ - "CVN", /* 0xffa2 */ - "FREE", /* 0xffa3 */ - "LOC", /* 0xffa4 */ - "LOF", /* 0xffa5 */ - "MKN$", /* 0xffa6 */ - "AS", /* 0xffa7 */ - "LPEEK", /* 0xffa8 */ - "BUTTON", /* 0xffa9 */ - "HPOINT", /* 0xffaa */ - "ERNO", /* 0xffab */ - "ERLIN" /* 0xffac */ -}; - -static const char *const dragonbas_statements[] = -{ - "FOR", /* 0x80 */ - "GO", /* 0x81 */ - "REM", /* 0x82 */ - "'", /* 0x83 */ - "ELSE", /* 0x84 */ - "IF", /* 0x85 */ - "DATA", /* 0x86 */ - "PRINT", /* 0x87 */ - "ON", /* 0x88 */ - "INPUT", /* 0x89 */ - "END", /* 0x8a */ - "NEXT", /* 0x8b */ - "DIM", /* 0x8c */ - "READ", /* 0x8d */ - "LET", /* 0x8e */ - "RUN", /* 0x8f */ - "RESTORE", /* 0x90 */ - "RETURN", /* 0x91 */ - "STOP", /* 0x92 */ - "POKE", /* 0x93 */ - "CONT", /* 0x94 */ - "LIST", /* 0x95 */ - "CLEAR", /* 0x96 */ - "NEW", /* 0x97 */ - "DEF", /* 0x98 */ - "CLOAD", /* 0x99 */ - "CSAVE", /* 0x9a */ - "OPEN", /* 0x9b */ - "CLOSE", /* 0x9c */ - "LLIST", /* 0x9d */ - "SET", /* 0x9e */ - "RESET", /* 0x9f */ - "CLS", /* 0xa0 */ - "MOTOR", /* 0xa1 */ - "SOUND", /* 0xa2 */ - "AUDIO", /* 0xa3 */ - "EXEC", /* 0xa4 */ - "SKIPF", /* 0xa5 */ - "DEL", /* 0xa6 */ - "EDIT", /* 0xa7 */ - "TRON", /* 0xa8 */ - "TROFF", /* 0xa9 */ - "LINE", /* 0xaa */ - "PCLS", /* 0xab */ - "PSET", /* 0xac */ - "PRESET", /* 0xad */ - "SCREEN", /* 0xae */ - "PCLEAR", /* 0xaf */ - "COLOR", /* 0xb0 */ - "CIRCLE", /* 0xb1 */ - "PAINT", /* 0xb2 */ - "GET", /* 0xb3 */ - "PUT", /* 0xb4 */ - "DRAW", /* 0xb5 */ - "PCOPY", /* 0xb6 */ - "PMODE", /* 0xb7 */ - "PLAY", /* 0xb8 */ - "DLOAD", /* 0xb9 */ - "RENUM", /* 0xba */ - "TAB(", /* 0xbb */ - "TO", /* 0xbc */ - "SUB", /* 0xbd */ - "FN", /* 0xbe */ - "THEN", /* 0xbf */ - "NOT", /* 0xc0 */ - "STEP", /* 0xc1 */ - "OFF", /* 0xc2 */ - "+", /* 0xc3 */ - "-", /* 0xc4 */ - "*", /* 0xc5 */ - "/", /* 0xc6 */ - "^", /* 0xc7 */ - "AND", /* 0xc8 */ - "OR", /* 0xc9 */ - ">", /* 0xca */ - "=", /* 0xcb */ - "<", /* 0xcc */ - "USING", /* 0xcd */ - "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[] = -{ - "SGN", /* 0xff80 */ - "INT", /* 0xff81 */ - "ABS", /* 0xff82 */ - "POS", /* 0xff83 */ - "RND", /* 0xff84 */ - "SQR", /* 0xff85 */ - "LOG", /* 0xff86 */ - "EXP", /* 0xff87 */ - "SIN", /* 0xff88 */ - "COS", /* 0xff89 */ - "TAN", /* 0xff8a */ - "ATN", /* 0xff8b */ - "PEEK", /* 0xff8c */ - "LEN", /* 0xff8d */ - "STR$", /* 0xff8e */ - "VAL", /* 0xff8f */ - "ASC", /* 0xff90 */ - "CHR$", /* 0xff91 */ - "EOF", /* 0xff92 */ - "JOYSTK", /* 0xff93 */ - "FIX", /* 0xff94 */ - "HEX$", /* 0xff95 */ - "LEFT$", /* 0xff96 */ - "RIGHT$", /* 0xff97 */ - "MID$", /* 0xff98 */ - "POINT", /* 0xff99 */ - "INKEY$", /* 0xff9a */ - "MEM", /* 0xff9b */ - "VARPTR", /* 0xff9c */ - "INSTR", /* 0xff9d */ - "TIMER", /* 0xff9e */ - "PPOINT", /* 0xff9f */ - "STRING$", /* 0xffa0 */ - "USR", /* 0xffa1 */ - "LOF", /* 0xffa2 */ - "FREE", /* 0xffa3 */ - "ERL", /* 0xffa4 */ - "ERR", /* 0xffa5 */ - "HIMEM", /* 0xffa6 */ - "LOC", /* 0xffa7 */ - "FRE$" /* 0xffa8 */ -}; - -static const char *const vzbas[] = -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "RESET", /* 0x82 */ - "SET", /* 0x83 */ - "CLS", /* 0x84 */ - nullptr, /* 0x85 */ - "RANDOM", /* 0x86 */ - "NEXT", /* 0x87 */ - "DATA", /* 0x88 */ - "INPUT", /* 0x89 */ - "DIM", /* 0x8a */ - "READ", /* 0x8b */ - "LET", /* 0x8c */ - "GOTO", /* 0x8d */ - "RUN", /* 0x8e */ - "IF", /* 0x8f */ - "RESTORE", /* 0x90 */ - "GOSUB", /* 0x91 */ - "RETURN", /* 0x92 */ - "'", /* 0x93 */ - "STOP", /* 0x94 */ - "ELSE", /* 0x95 */ - "COPY", /* 0x96 */ - "COLOR", /* 0x97 */ - "VERIFY", /* 0x98 */ - "DEFINT", /* 0x99 */ - "DEFSNG", /* 0x9a */ - "DEFDBL", /* 0x9b */ - "CRUN", /* 0x9c */ - "MODE", /* 0x9d */ - "ERROR", /* 0x9e */ - "RESUME", /* 0x9f */ - "OUT", /* 0xa0 */ - "IN", /* 0xa1 */ - nullptr, /* 0xa2 */ - nullptr, /* 0xa3 */ - nullptr, /* 0xa4 */ - nullptr, /* 0xa5 */ - nullptr, /* 0xa6 */ - nullptr, /* 0xa7 */ - nullptr, /* 0xa8 */ - nullptr, /* 0xa9 */ - nullptr, /* 0xaa */ - nullptr, /* 0xab */ - nullptr, /* 0xac */ - nullptr, /* 0xad */ - "(RESET)", /* 0xae */ - "LPRINT", /* 0xaf */ - nullptr, /* 0xb0 */ - "POKE", /* 0xb1 */ - "PRINT", /* 0xb2 */ - "CONT", /* 0xb3 */ - "LIST", /* 0xb4 */ - "LLIST", /* 0xb5 */ - "DELETE", /* 0xb6 */ - "AUTO", /* 0xb7 */ - "CLEAR", /* 0xb8 */ - "CLOAD", /* 0xb9 */ - "CSAVE", /* 0xba */ - "NEW", /* 0xbb */ - "TAB(", /* 0xbc */ - "TO", /* 0xbd */ - nullptr, /* 0xbe */ - "USING", /* 0xbf */ - "VARPTR", /* 0xc0 */ - "USR", /* 0xc1 */ - "ERL", /* 0xc2 */ - "ERR", /* 0xc3 */ - "STRING$", /* 0xc4 */ - nullptr, /* 0xc5 */ - "POINT", /* 0xc6 */ - nullptr, /* 0xc7 */ - "MEM", /* 0xc8 */ - "INKEY$", /* 0xc9 */ - "THEN", /* 0xca */ - "NOT", /* 0xcb */ - "STEP", /* 0xcc */ - "+", /* 0xcd */ - "-", /* 0xce */ - "*", /* 0xcf */ - "/", /* 0xd0 */ - "^", /* 0xd1 */ - "AND", /* 0xd2 */ - "OR", /* 0xd3 */ - ">", /* 0xd4 */ - "=", /* 0xd5 */ - "<", /* 0xd6 */ - "SGN", /* 0xd7 */ - "INT", /* 0xd8 */ - "ABS", /* 0xd9 */ - "FRE", /* 0xda */ - "INP", /* 0xdb */ - "POS", /* 0xdc */ - "SQR", /* 0xdd */ - "AND", /* 0xde */ - "LOG", /* 0xdf */ - "EXP", /* 0xe0 */ - "COS", /* 0xe1 */ - "SIN", /* 0xe2 */ - "TAN", /* 0xe3 */ - "ATN", /* 0xe4 */ - "PEEK", /* 0xe5 */ - nullptr, /* 0xe6 */ - nullptr, /* 0xe7 */ - nullptr, /* 0xe8 */ - nullptr, /* 0xe9 */ - nullptr, /* 0xea */ - nullptr, /* 0xeb */ - nullptr, /* 0xec */ - nullptr, /* 0xed */ - nullptr, /* 0xee */ - "CINT", /* 0xef */ - "CSNG", /* 0xf0 */ - "CDBL", /* 0xf1 */ - "FIX", /* 0xf2 */ - "LEN", /* 0xf3 */ - "STR$", /* 0xf4 */ - "VAL", /* 0xf5 */ - "ASC", /* 0xf6 */ - "CHR$", /* 0xf7 */ - "LEFT$", /* 0xf8 */ - "RIGHT$", /* 0xf9 */ - "MID$", /* 0xfa */ - nullptr, /* 0xfb */ - nullptr, /* 0xfc */ - nullptr, /* 0xfd */ - nullptr, /* 0xfe */ - nullptr /* 0xff */ -}; - -static const char *const bml3bas_statements[] = -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "NEXT", /* 0x82 */ - "DATA", /* 0x83 */ - "DIM", /* 0x84 */ - "READ", /* 0x85 */ - "LET", /* 0x86 */ - "GO", /* 0x87 */ - "RUN", /* 0x88 */ - "IF", /* 0x89 */ - "RESTORE", /* 0x8a */ - "RETURN", /* 0x8b */ - "REM", /* 0x8c */ - "'", /* 0x8d */ - "STOP", /* 0x8e */ - "ELSE", /* 0x8f */ - "TRON", /* 0x90 */ - "TROFF", /* 0x91 */ - "SWAP", /* 0x92 */ - "DEFSTR", /* 0x93 */ - "DEFINT", /* 0x94 */ - "DEFSNG", /* 0x95 */ - "DEFDBL", /* 0x96 */ - "ON", /* 0x97 */ - "WAIT", /* 0x98 */ - "RENUM", /* 0x99 */ - "EDIT", /* 0x9a */ - "ERROR", /* 0x9b */ - "RESUME", /* 0x9c */ - "AUTO", /* 0x9d */ - "DELETE", /* 0x9e */ - "TERM", /* 0x9f */ - "WIDTH", /* 0xa0 */ - "UNLIST", /* 0xa1 */ - "MON", /* 0xa2 */ - "LOCATE", /* 0xa3 */ - "CLS", /* 0xa4 */ - "CONSOLE", /* 0xa5 */ - "PSET", /* 0xa6 */ - "PRESET", /* 0xa7 */ - "MOTOR", /* 0xa8 */ - "SKIPF", /* 0xa9 */ - "SAVE", /* 0xaa */ - "LOAD", /* 0xab */ - "MERGE", /* 0xac */ - "EXEC", /* 0xad */ - "OPEN", /* 0xae */ - "CLOSE", /* 0xaf */ - "FILES", /* 0xb0 */ - "COM", /* 0xb1 */ - "KEY", /* 0xb2 */ - "PAINT", /* 0xb3 */ - "BEEP", /* 0xb4 */ - "COLOR", /* 0xb5 */ - "LINE", /* 0xb6 */ - "DEF", /* 0xb7 */ - "POKE", /* 0xb8 */ - "PRINT", /* 0xb9 */ - "CONT", /* 0xba */ - "LIST", /* 0xbb */ - "CLEAR", /* 0xbc */ - "RANDOMIZE",/* 0xbd */ - "WHILE", /* 0xbe */ - "WEND", /* 0xbf */ - "NEW", /* 0xc0 */ - "TAB(", /* 0xc1 */ - "TO", /* 0xc2 */ - "SUB", /* 0xc3 */ - "FN", /* 0xc4 */ - "SPC(", /* 0xc5 */ - "USING", /* 0xc6 */ - "USR", /* 0xc7 */ - "ERL", /* 0xc8 */ - "ERR", /* 0xc9 */ - "OFF", /* 0xca */ - "THEN", /* 0xcb */ - "NOT", /* 0xcc */ - "STEP", /* 0xcd */ - "+", /* 0xce */ - "-", /* 0xcf */ - "*", /* 0xd0 */ - "/", /* 0xd1 */ - "^", /* 0xd2 */ - "AND", /* 0xd3 */ - "OR", /* 0xd4 */ - "XOR", /* 0xd5 */ - "EQV", /* 0xd6 */ - "IMP", /* 0xd7 */ - "MOD", /* 0xd8 */ - "\\", /* 0xd9 */ - ">", /* 0xda */ - "=", /* 0xdb */ - "<" /* 0xdc */ -}; - -static const char *const bml3bas_functions[] = -{ - "SGN", /* 0xff80 */ - "INT", /* 0xff81 */ - "ABS", /* 0xff82 */ - "FRE", /* 0xff83 */ - "POS", /* 0xff84 */ - "SQR", /* 0xff85 */ - "LOG", /* 0xff86 */ - "EXP", /* 0xff87 */ - "COS", /* 0xff88 */ - "SIN", /* 0xff89 */ - "TAN", /* 0xff8a */ - "ATN", /* 0xff8b */ - "PEEK", /* 0xff8c */ - "LEN", /* 0xff8d */ - "STR$", /* 0xff8e */ - "VAL", /* 0xff8f */ - "ASC", /* 0xff90 */ - "CHR$", /* 0xff91 */ - "CINT", /* 0xff92 */ - "CSNG", /* 0xff93 */ - "CDBL", /* 0xff94 */ - "FIX", /* 0xff95 */ - "SPACE$", /* 0xff96 */ - "HEX$", /* 0xff97 */ - "OCT$", /* 0xff98 */ - "LOF", /* 0xff99 */ - "EOF", /* 0xff9a */ - "PEN", /* 0xff9b */ - "LEFT$", /* 0xff9c */ - "RIGHT$", /* 0xff9d */ - "MID$", /* 0xff9e */ - "INSTR", /* 0xff9f */ - "SCREEN", /* 0xffa0 */ - "VARPTR", /* 0xffa1 */ - "STRING$", /* 0xffa2 */ - "RND", /* 0xffa3 */ - "INKEY$", /* 0xffa4 */ - "INPUT", /* 0xffa5 */ - "CSRLIN", /* 0xffa6 */ - "POINT", /* 0xffa7 */ - "TIME", /* 0xffa8 */ - "DATE" /* 0xffa9 */ -}; - - -#ifdef BASIC_ -/* ----------------------------------------------------------------------- * - * CBM machines * - * ----------------------------------------------------------------------- */ -static const char *const basic_10[] = /* "BASIC 1.0" - supported by pet */ -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "NEXT", /* 0x82 */ - "DATA", /* 0x83 */ - "INPUT#", /* 0x84 */ - "INPUT", /* 0x85 */ - "DIM", /* 0x86 */ - "READ", /* 0x87 */ - "LET", /* 0x88 */ - "GOTO", /* 0x89 */ - "RUN", /* 0x8a */ - "IF", /* 0x8b */ - "RESTORE", /* 0x8c */ - "GOSUB", /* 0x8d */ - "RETURN", /* 0x8e */ - "REM", /* 0x8f */ - "STOP", /* 0x90 */ - "ON", /* 0x91 */ - "WAIT", /* 0x92 */ - "LOAD", /* 0x93 */ - "SAVE", /* 0x94 */ - "VERIFY", /* 0x95 */ - "DEF", /* 0x96 */ - "POKE", /* 0x97 */ - "PRINT#", /* 0x98 */ - "PRINT", /* 0x99 */ - "CONT", /* 0x9a */ - "LIST", /* 0x9b */ - "CLR", /* 0x9c */ - "CMD", /* 0x9d */ - "SYS", /* 0x9e */ - "OPEN", /* 0x9f */ - "CLOSE", /* 0xa0 */ - "GET", /* 0xa1 */ - "NEW", /* 0xa2 */ - "TAB(", /* 0xa3 */ - "TO", /* 0xa4 */ - "FN", /* 0xa5 */ - "SPC(", /* 0xa6 */ - "THEN", /* 0xa7 */ - "NOT", /* 0xa8 */ - "STEP", /* 0xa9 */ - "+", /* 0xaa */ - "-", /* 0xab */ - "*", /* 0xac */ - "/", /* 0xad */ - "^", /* 0xae */ - "AND", /* 0xaf */ - "OR", /* 0xb0 */ - ">", /* 0xb1 */ - "=", /* 0xb2 */ - "<", /* 0xb3 */ - "SGN", /* 0xb4 */ - "INT", /* 0xb5 */ - "ABS", /* 0xb6 */ - "USR", /* 0xb7 */ - "FRE", /* 0xb8 */ - "POS", /* 0xb9 */ - "SQR", /* 0xba */ - "RND", /* 0xbb */ - "LOG", /* 0xbc */ - "EXP", /* 0xbd */ - "COS", /* 0xbe */ - "SIN", /* 0xbf */ - "TAN", /* 0xc0 */ - "ATN", /* 0xc1 */ - "PEEK", /* 0xc2 */ - "LEN", /* 0xc3 */ - "STR$", /* 0xc4 */ - "VAL", /* 0xc5 */ - "ASC", /* 0xc6 */ - "CHR$", /* 0xc7 */ - "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 */ - "{PI}" /* 0xff - A single character shaped as greek lowercase 'PI' */ -}; - -static const char *const basic_20[] = /* "BASIC 2.0" - supported by vic20 & clones, c64 & clones, cbm30xx series */ -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "NEXT", /* 0x82 */ - "DATA", /* 0x83 */ - "INPUT#", /* 0x84 */ - "INPUT", /* 0x85 */ - "DIM", /* 0x86 */ - "READ", /* 0x87 */ - "LET", /* 0x88 */ - "GOTO", /* 0x89 */ - "RUN", /* 0x8a */ - "IF", /* 0x8b */ - "RESTORE", /* 0x8c */ - "GOSUB", /* 0x8d */ - "RETURN", /* 0x8e */ - "REM", /* 0x8f */ - "STOP", /* 0x90 */ - "ON", /* 0x91 */ - "WAIT", /* 0x92 */ - "LOAD", /* 0x93 */ - "SAVE", /* 0x94 */ - "VERIFY", /* 0x95 */ - "DEF", /* 0x96 */ - "POKE", /* 0x97 */ - "PRINT#", /* 0x98 */ - "PRINT", /* 0x99 */ - "CONT", /* 0x9a */ - "LIST", /* 0x9b */ - "CLR", /* 0x9c */ - "CMD", /* 0x9d */ - "SYS", /* 0x9e */ - "OPEN", /* 0x9f */ - "CLOSE", /* 0xa0 */ - "GET", /* 0xa1 */ - "NEW", /* 0xa2 */ - "TAB(", /* 0xa3 */ - "TO", /* 0xa4 */ - "FN", /* 0xa5 */ - "SPC(", /* 0xa6 */ - "THEN", /* 0xa7 */ - "NOT", /* 0xa8 */ - "STEP", /* 0xa9 */ - "+", /* 0xaa */ - "-", /* 0xab */ - "*", /* 0xac */ - "/", /* 0xad */ - "^", /* 0xae */ - "AND", /* 0xaf */ - "OR", /* 0xb0 */ - ">", /* 0xb1 */ - "=", /* 0xb2 */ - "<", /* 0xb3 */ - "SGN", /* 0xb4 */ - "INT", /* 0xb5 */ - "ABS", /* 0xb6 */ - "USR", /* 0xb7 */ - "FRE", /* 0xb8 */ - "POS", /* 0xb9 */ - "SQR", /* 0xba */ - "RND", /* 0xbb */ - "LOG", /* 0xbc */ - "EXP", /* 0xbd */ - "COS", /* 0xbe */ - "SIN", /* 0xbf */ - "TAN", /* 0xc0 */ - "ATN", /* 0xc1 */ - "PEEK", /* 0xc2 */ - "LEN", /* 0xc3 */ - "STR$", /* 0xc4 */ - "VAL", /* 0xc5 */ - "ASC", /* 0xc6 */ - "CHR$", /* 0xc7 */ - "LEFT$", /* 0xc8 */ - "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 */ - "{PI}" /* 0xff - A single character shaped as greek lowercase 'PI' */ -}; - -static const char *const basic_20_super_expander_vic[] = /* "BASIC 2.0 with Super Expander" - supported by vic20 & clones */ -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "NEXT", /* 0x82 */ - "DATA", /* 0x83 */ - "INPUT#", /* 0x84 */ - "INPUT", /* 0x85 */ - "DIM", /* 0x86 */ - "READ", /* 0x87 */ - "LET", /* 0x88 */ - "GOTO", /* 0x89 */ - "RUN", /* 0x8a */ - "IF", /* 0x8b */ - "RESTORE", /* 0x8c */ - "GOSUB", /* 0x8d */ - "RETURN", /* 0x8e */ - "REM", /* 0x8f */ - "STOP", /* 0x90 */ - "ON", /* 0x91 */ - "WAIT", /* 0x92 */ - "LOAD", /* 0x93 */ - "SAVE", /* 0x94 */ - "VERIFY", /* 0x95 */ - "DEF", /* 0x96 */ - "POKE", /* 0x97 */ - "PRINT#", /* 0x98 */ - "PRINT", /* 0x99 */ - "CONT", /* 0x9a */ - "LIST", /* 0x9b */ - "CLR", /* 0x9c */ - "CMD", /* 0x9d */ - "SYS", /* 0x9e */ - "OPEN", /* 0x9f */ - "CLOSE", /* 0xa0 */ - "GET", /* 0xa1 */ - "NEW", /* 0xa2 */ - "TAB(", /* 0xa3 */ - "TO", /* 0xa4 */ - "FN", /* 0xa5 */ - "SPC(", /* 0xa6 */ - "THEN", /* 0xa7 */ - "NOT", /* 0xa8 */ - "STEP", /* 0xa9 */ - "+", /* 0xaa */ - "-", /* 0xab */ - "*", /* 0xac */ - "/", /* 0xad */ - "^", /* 0xae */ - "AND", /* 0xaf */ - "OR", /* 0xb0 */ - ">", /* 0xb1 */ - "=", /* 0xb2 */ - "<", /* 0xb3 */ - "SGN", /* 0xb4 */ - "INT", /* 0xb5 */ - "ABS", /* 0xb6 */ - "USR", /* 0xb7 */ - "FRE", /* 0xb8 */ - "POS", /* 0xb9 */ - "SQR", /* 0xba */ - "RND", /* 0xbb */ - "LOG", /* 0xbc */ - "EXP", /* 0xbd */ - "COS", /* 0xbe */ - "SIN", /* 0xbf */ - "TAN", /* 0xc0 */ - "ATN", /* 0xc1 */ - "PEEK", /* 0xc2 */ - "LEN", /* 0xc3 */ - "STR$", /* 0xc4 */ - "VAL", /* 0xc5 */ - "ASC", /* 0xc6 */ - "CHR$", /* 0xc7 */ - "LEFT$", /* 0xc8 */ - "RIGHT$", /* 0xc9 */ - "MID$", /* 0xca */ - "GO", /* 0xcb */ - "KEY", /* 0xcc */ - "GRAPHIC", /* 0xcd */ - "SCNCLR", /* 0xce */ - "CIRCLE", /* 0xcf */ - "DRAW", /* 0xd0 */ - "REGION", /* 0xd1 */ - "COLOR", /* 0xd2 */ - "POINT", /* 0xd3 */ - "SOUND", /* 0xd4 */ - "CHAR", /* 0xd5 */ - "PAINT", /* 0xd6 */ - "RPOT", /* 0xd7 */ - "RPEN", /* 0xd8 */ - "RSND", /* 0xd9 */ - "RCOLR", /* 0xda */ - "RGR", /* 0xdb */ - "RJOY", /* 0xdc */ - "RDOT", /* 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 */ - "{PI}" /* 0xff - A single character shaped as greek lowercase 'PI' */ -}; - -static const char *const basic_20_turtle_basic_10[] = /* "BASIC 2.0 with Turtle BASIC 1.0" - supported by vic20 & clones */ -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "NEXT", /* 0x82 */ - "DATA", /* 0x83 */ - "INPUT#", /* 0x84 */ - "INPUT", /* 0x85 */ - "DIM", /* 0x86 */ - "READ", /* 0x87 */ - "LET", /* 0x88 */ - "GOTO", /* 0x89 */ - "RUN", /* 0x8a */ - "IF", /* 0x8b */ - "RESTORE", /* 0x8c */ - "GOSUB", /* 0x8d */ - "RETURN", /* 0x8e */ - "REM", /* 0x8f */ - "STOP", /* 0x90 */ - "ON", /* 0x91 */ - "WAIT", /* 0x92 */ - "LOAD", /* 0x93 */ - "SAVE", /* 0x94 */ - "VERIFY", /* 0x95 */ - "DEF", /* 0x96 */ - "POKE", /* 0x97 */ - "PRINT#", /* 0x98 */ - "PRINT", /* 0x99 */ - "CONT", /* 0x9a */ - "LIST", /* 0x9b */ - "CLR", /* 0x9c */ - "CMD", /* 0x9d */ - "SYS", /* 0x9e */ - "OPEN", /* 0x9f */ - "CLOSE", /* 0xa0 */ - "GET", /* 0xa1 */ - "NEW", /* 0xa2 */ - "TAB(", /* 0xa3 */ - "TO", /* 0xa4 */ - "FN", /* 0xa5 */ - "SPC(", /* 0xa6 */ - "THEN", /* 0xa7 */ - "NOT", /* 0xa8 */ - "STEP", /* 0xa9 */ - "+", /* 0xaa */ - "-", /* 0xab */ - "*", /* 0xac */ - "/", /* 0xad */ - "^", /* 0xae */ - "AND", /* 0xaf */ - "OR", /* 0xb0 */ - ">", /* 0xb1 */ - "=", /* 0xb2 */ - "<", /* 0xb3 */ - "SGN", /* 0xb4 */ - "INT", /* 0xb5 */ - "ABS", /* 0xb6 */ - "USR", /* 0xb7 */ - "FRE", /* 0xb8 */ - "POS", /* 0xb9 */ - "SQR", /* 0xba */ - "RND", /* 0xbb */ - "LOG", /* 0xbc */ - "EXP", /* 0xbd */ - "COS", /* 0xbe */ - "SIN", /* 0xbf */ - "TAN", /* 0xc0 */ - "ATN", /* 0xc1 */ - "PEEK", /* 0xc2 */ - "LEN", /* 0xc3 */ - "STR$", /* 0xc4 */ - "VAL", /* 0xc5 */ - "ASC", /* 0xc6 */ - "CHR$", /* 0xc7 */ - "LEFT$", /* 0xc8 */ - "RIGHT$", /* 0xc9 */ - "MID$", /* 0xca */ - "GO", /* 0xcb */ - "GRAPHIC", /* 0xcc */ - "OLD", /* 0xcd */ - "TURN", /* 0xce */ - "PEN", /* 0xcf */ - "DRAW", /* 0xd0 */ - "MOVE", /* 0xd1 */ - "POINT", /* 0xd2 */ - "KILL", /* 0xd3 */ - "WRITE", /* 0xd4 */ - "REPEAT", /* 0xd5 */ - "SCREEN", /* 0xd6 */ - "DOKE", /* 0xd7 */ - "RELOC", /* 0xd8 */ - "FILL", /* 0xd9 */ - "RTIME", /* 0xda */ - "BASE", /* 0xdb */ - "PAUSE", /* 0xdc */ - "POP", /* 0xdd */ - "COLOR", /* 0xde */ - "MERGE", /* 0xdf */ - "CHAR", /* 0xe0 */ - "TAKE", /* 0xe1 */ - "SOUND", /* 0xe2 */ - "VOL", /* 0xe3 */ - "PUT", /* 0xe4 */ - "PLACE", /* 0xe5 */ - "CLS", /* 0xe6 */ - "ACCEPT", /* 0xe7 */ - "RESET", /* 0xe8 */ - "GRAB", /* 0xe9 */ - "RDOT", /* 0xea */ - "PLR$", /* 0xeb */ - "DEEK", /* 0xec */ - "JOY", /* 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 */ - "{PI}" /* 0xff - A single character shaped as greek lowercase 'PI' */ -}; - -static const char *const basic_20_speech_basic_27[] = /* "BASIC 2.0 with Speech BASIC 2.7" - supported by c64 & clones */ -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "NEXT", /* 0x82 */ - "DATA", /* 0x83 */ - "INPUT#", /* 0x84 */ - "INPUT", /* 0x85 */ - "DIM", /* 0x86 */ - "READ", /* 0x87 */ - "LET", /* 0x88 */ - "GOTO", /* 0x89 */ - "RUN", /* 0x8a */ - "IF", /* 0x8b */ - "RESTORE", /* 0x8c */ - "GOSUB", /* 0x8d */ - "RETURN", /* 0x8e */ - "REM", /* 0x8f */ - "STOP", /* 0x90 */ - "ON", /* 0x91 */ - "WAIT", /* 0x92 */ - "LOAD", /* 0x93 */ - "SAVE", /* 0x94 */ - "VERIFY", /* 0x95 */ - "DEF", /* 0x96 */ - "POKE", /* 0x97 */ - "PRINT#", /* 0x98 */ - "PRINT", /* 0x99 */ - "CONT", /* 0x9a */ - "LIST", /* 0x9b */ - "CLR", /* 0x9c */ - "CMD", /* 0x9d */ - "SYS", /* 0x9e */ - "OPEN", /* 0x9f */ - "CLOSE", /* 0xa0 */ - "GET", /* 0xa1 */ - "NEW", /* 0xa2 */ - "TAB(", /* 0xa3 */ - "TO", /* 0xa4 */ - "FN", /* 0xa5 */ - "SPC(", /* 0xa6 */ - "THEN", /* 0xa7 */ - "NOT", /* 0xa8 */ - "STEP", /* 0xa9 */ - "+", /* 0xaa */ - "-", /* 0xab */ - "*", /* 0xac */ - "/", /* 0xad */ - "^", /* 0xae */ - "AND", /* 0xaf */ - "OR", /* 0xb0 */ - ">", /* 0xb1 */ - "=", /* 0xb2 */ - "<", /* 0xb3 */ - "SGN", /* 0xb4 */ - "INT", /* 0xb5 */ - "ABS", /* 0xb6 */ - "USR", /* 0xb7 */ - "FRE", /* 0xb8 */ - "POS", /* 0xb9 */ - "SQR", /* 0xba */ - "RND", /* 0xbb */ - "LOG", /* 0xbc */ - "EXP", /* 0xbd */ - "COS", /* 0xbe */ - "SIN", /* 0xbf */ - "TAN", /* 0xc0 */ - "ATN", /* 0xc1 */ - "PEEK", /* 0xc2 */ - "LEN", /* 0xc3 */ - "STR$", /* 0xc4 */ - "VAL", /* 0xc5 */ - "ASC", /* 0xc6 */ - "CHR$", /* 0xc7 */ - "LEFT$", /* 0xc8 */ - "RIGHT$", /* 0xc9 */ - "MID$", /* 0xca */ - "GO", /* 0xcb */ - "RESET", /* 0xcc */ - "BASIC", /* 0xcd */ - "HELP", /* 0xce */ - "KEY", /* 0xcf */ - "HIMEM", /* 0xd0 */ - "DISK", /* 0xd1 */ - "DIR", /* 0xd2 */ - "BLOAD", /* 0xd3 */ - "BSAVE", /* 0xd4 */ - "MAP", /* 0xd5 */ - "MEM", /* 0xd6 */ - "PAUSE", /* 0xd7 */ - "BLOCK", /* 0xd8 */ - "HEAR", /* 0xd9 */ - "RECORD", /* 0xda */ - "PLAY", /* 0xdb */ - "VOLDEF", /* 0xdc */ - "COLDEF", /* 0xdd */ - "HEX", /* 0xde */ - "DEZ", /* 0xdf */ - "SCREEN", /* 0xe0 */ - "EXEC", /* 0xe1 */ - "MON", /* 0xe2 */ - "{LEFT ARROW}", /* 0xe3 - A single character shaped as a left pointing arrow */ - "FROM", /* 0xe4 */ - "SPEED", /* 0xe5 */ - "OFF", /* 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 */ - "{PI}" /* 0xff - A single character shaped as greek lowercase 'PI' */ -}; - -static const char *const basic_20_at_basic[] = /* "BASIC 2.0 with @BASIC" - supported by c64 & clones */ -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "NEXT", /* 0x82 */ - "DATA", /* 0x83 */ - "INPUT#", /* 0x84 */ - "INPUT", /* 0x85 */ - "DIM", /* 0x86 */ - "READ", /* 0x87 */ - "LET", /* 0x88 */ - "GOTO", /* 0x89 */ - "RUN", /* 0x8a */ - "IF", /* 0x8b */ - "RESTORE", /* 0x8c */ - "GOSUB", /* 0x8d */ - "RETURN", /* 0x8e */ - "REM", /* 0x8f */ - "STOP", /* 0x90 */ - "ON", /* 0x91 */ - "WAIT", /* 0x92 */ - "LOAD", /* 0x93 */ - "SAVE", /* 0x94 */ - "VERIFY", /* 0x95 */ - "DEF", /* 0x96 */ - "POKE", /* 0x97 */ - "PRINT#", /* 0x98 */ - "PRINT", /* 0x99 */ - "CONT", /* 0x9a */ - "LIST", /* 0x9b */ - "CLR", /* 0x9c */ - "CMD", /* 0x9d */ - "SYS", /* 0x9e */ - "OPEN", /* 0x9f */ - "CLOSE", /* 0xa0 */ - "GET", /* 0xa1 */ - "NEW", /* 0xa2 */ - "TAB(", /* 0xa3 */ - "TO", /* 0xa4 */ - "FN", /* 0xa5 */ - "SPC(", /* 0xa6 */ - "THEN", /* 0xa7 */ - "NOT", /* 0xa8 */ - "STEP", /* 0xa9 */ - "+", /* 0xaa */ - "-", /* 0xab */ - "*", /* 0xac */ - "/", /* 0xad */ - "^", /* 0xae */ - "AND", /* 0xaf */ - "OR", /* 0xb0 */ - ">", /* 0xb1 */ - "=", /* 0xb2 */ - "<", /* 0xb3 */ - "SGN", /* 0xb4 */ - "INT", /* 0xb5 */ - "ABS", /* 0xb6 */ - "USR", /* 0xb7 */ - "FRE", /* 0xb8 */ - "POS", /* 0xb9 */ - "SQR", /* 0xba */ - "RND", /* 0xbb */ - "LOG", /* 0xbc */ - "EXP", /* 0xbd */ - "COS", /* 0xbe */ - "SIN", /* 0xbf */ - "TAN", /* 0xc0 */ - "ATN", /* 0xc1 */ - "PEEK", /* 0xc2 */ - "LEN", /* 0xc3 */ - "STR$", /* 0xc4 */ - "VAL", /* 0xc5 */ - "ASC", /* 0xc6 */ - "CHR$", /* 0xc7 */ - "LEFT$", /* 0xc8 */ - "RIGHT$", /* 0xc9 */ - "MID$", /* 0xca */ - "GO", /* 0xcb */ - "TRACE", /* 0xcc */ - "DELETE", /* 0xcd */ - "AUTO", /* 0xce */ - "OLD", /* 0xcf */ - "DUMP", /* 0xd0 */ - "FIND", /* 0xd1 */ - "RENUMBER", /* 0xd2 */ - "DLOAD", /* 0xd3 */ - "DSAVE", /* 0xd4 */ - "DVERIFY", /* 0xd5 */ - "DIRECTORY" /* 0xd6 */ - "CATALOG", /* 0xd7 */ - "SCRATCH", /* 0xd8 */ - "COLLECT", /* 0xd9 */ - "RENAME", /* 0xda */ - "COPY", /* 0xdb */ - "BACKUP", /* 0xdc */ - "DISK", /* 0xdd */ - "HEADER", /* 0xde */ - "APPEND", /* 0xdf */ - "MERGE", /* 0xe0 */ - "MLOAD", /* 0xe1 */ - "MVERIFY", /* 0xe2 */ - "MSAVE", /* 0xe3 */ - "KEY", /* 0xe4 */ - "BASIC", /* 0xe5 */ - "RESET", /* 0xe6 */ - "EXIT", /* 0xe7 */ - "ENTER", /* 0xe8 */ - "DOKE", /* 0xe9 */ - "SET", /* 0xea */ - "HELP", /* 0xeb */ - "SCREEN", /* 0xec */ - "LOMEM", /* 0xed */ - "HIMEM", /* 0xee */ - "COLOUR", /* 0xef */ - "TYPE", /* 0xf0 */ - "TIME", /* 0xf1 */ - "DEEK", /* 0xf2 */ - "HEX$", /* 0xf3 */ - "BIN$", /* 0xf4 */ - "OFF", /* 0xf5 */ - "ALARM", /* 0xf6 */ - NULL, /* 0xf7 */ - NULL, /* 0xf8 */ - NULL, /* 0xf9 */ - NULL, /* 0xfa */ - NULL, /* 0xfb */ - NULL, /* 0xfc */ - NULL, /* 0xfd */ - NULL, /* 0xfe */ - "{PI}" /* 0xff - A single character shaped as greek lowercase 'PI' */ -}; - -static const char *const basic_20_simon_s_basic[] = /* "BASIC 2.0 with Simon's BASIC" - supported by c64 & clones */ -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "NEXT", /* 0x82 */ - "DATA", /* 0x83 */ - "INPUT#", /* 0x84 */ - "INPUT", /* 0x85 */ - "DIM", /* 0x86 */ - "READ", /* 0x87 */ - "LET", /* 0x88 */ - "GOTO", /* 0x89 */ - "RUN", /* 0x8a */ - "IF", /* 0x8b */ - "RESTORE", /* 0x8c */ - "GOSUB", /* 0x8d */ - "RETURN", /* 0x8e */ - "REM", /* 0x8f */ - "STOP", /* 0x90 */ - "ON", /* 0x91 */ - "WAIT", /* 0x92 */ - "LOAD", /* 0x93 */ - "SAVE", /* 0x94 */ - "VERIFY", /* 0x95 */ - "DEF", /* 0x96 */ - "POKE", /* 0x97 */ - "PRINT#", /* 0x98 */ - "PRINT", /* 0x99 */ - "CONT", /* 0x9a */ - "LIST", /* 0x9b */ - "CLR", /* 0x9c */ - "CMD", /* 0x9d */ - "SYS", /* 0x9e */ - "OPEN", /* 0x9f */ - "CLOSE", /* 0xa0 */ - "GET", /* 0xa1 */ - "NEW", /* 0xa2 */ - "TAB(", /* 0xa3 */ - "TO", /* 0xa4 */ - "FN", /* 0xa5 */ - "SPC(", /* 0xa6 */ - "THEN", /* 0xa7 */ - "NOT", /* 0xa8 */ - "STEP", /* 0xa9 */ - "+", /* 0xaa */ - "-", /* 0xab */ - "*", /* 0xac */ - "/", /* 0xad */ - "^", /* 0xae */ - "AND", /* 0xaf */ - "OR", /* 0xb0 */ - ">", /* 0xb1 */ - "=", /* 0xb2 */ - "<", /* 0xb3 */ - "SGN", /* 0xb4 */ - "INT", /* 0xb5 */ - "ABS", /* 0xb6 */ - "USR", /* 0xb7 */ - "FRE", /* 0xb8 */ - "POS", /* 0xb9 */ - "SQR", /* 0xba */ - "RND", /* 0xbb */ - "LOG", /* 0xbc */ - "EXP", /* 0xbd */ - "COS", /* 0xbe */ - "SIN", /* 0xbf */ - "TAN", /* 0xc0 */ - "ATN", /* 0xc1 */ - "PEEK", /* 0xc2 */ - "LEN", /* 0xc3 */ - "STR$", /* 0xc4 */ - "VAL", /* 0xc5 */ - "ASC", /* 0xc6 */ - "CHR$", /* 0xc7 */ - "LEFT$", /* 0xc8 */ - "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 */ - "{PI}", /* 0xff - A single character shaped as greek lowercase 'PI' */ - NULL, /* 0x6400 */ - "HIRES", /* 0x6401 */ - "PLOT", /* 0x6402 */ - "LINE", /* 0x6403 */ - "BLOCK", /* 0x6404 */ - "FCHR", /* 0x6405 */ - "FCOL", /* 0x6406 */ - "FILL", /* 0x6407 */ - "REC", /* 0x6408 */ - "ROT", /* 0x6409 */ - "DRAW", /* 0x640a */ - "CHAR", /* 0x640b */ - "HI COL", /* 0x640c */ - "INV", /* 0x640d */ - "FRAC", /* 0x640e */ - "MOVE", /* 0x640f */ - "PLACE", /* 0x6410 */ - "UPB", /* 0x6411 */ - "UPW", /* 0x6412 */ - "LEFTW", /* 0x6413 */ - "LEFTB", /* 0x6414 */ - "DOWNB", /* 0x6415 */ - "DOWNW", /* 0x6416 */ - "RIGHTB", /* 0x6417 */ - "RIGHTW", /* 0x6418 */ - "MULTI", /* 0x6419 */ - "COLOUR", /* 0x641a */ - "MMOB", /* 0x641b */ - "BFLASH", /* 0x641c */ - "MOB SET", /* 0x641d */ - "MUSIC", /* 0x641e */ - "FLASH", /* 0x641f */ - "REPEAT", /* 0x6420 */ - "PLAY", /* 0x6421 */ - ">>", /* 0x6422 */ - "CENTRE", /* 0x6423 */ - "ENVELOPE", /* 0x6424 */ - "CGOTO", /* 0x6425 */ - "WAVE", /* 0x6426 */ - "FETCH", /* 0x6427 */ - "AT(", /* 0x6428 */ - "UNTIL", /* 0x6429 */ - ">>", /* 0x642a */ - ">>", /* 0x642b */ - "USE", /* 0x642c */ - ">>", /* 0x642d */ - "GLOBAL", /* 0x642e */ - ">>", /* 0x642f */ - "RESET", /* 0x6430 */ - "PROC", /* 0x6431 */ - "CALL", /* 0x6432 */ - "EXEC", /* 0x6433 */ - "END PROC", /* 0x6434 */ - "EXIT", /* 0x6435 */ - "END LOOP", /* 0x6436 */ - "ON KEY", /* 0x6437 */ - "DISABLE", /* 0x6438 */ - "RESUME", /* 0x6439 */ - "LOOP", /* 0x643a */ - "DELAY", /* 0x643b */ - ">>", /* 0x643c */ - ">>", /* 0x643d */ - ">>", /* 0x643e */ - ">>", /* 0x643f */ - "SECURE", /* 0x6440 */ - "DISAPA", /* 0x6441 */ - "CIRCLE", /* 0x6442 */ - "ON ERROR", /* 0x6443 */ - "NO ERROR", /* 0x6444 */ - "LOCAL", /* 0x6445 */ - "RCOMP", /* 0x6446 */ - "ELSE", /* 0x6447 */ - "RETRACE", /* 0x6448 */ - "TRACE", /* 0x6449 */ - "DIR", /* 0x644a */ - "PAGE", /* 0x644b */ - "DUMP", /* 0x644c */ - "FIND", /* 0x644d */ - "OPTION", /* 0x644e */ - "AUTO", /* 0x644f */ - "OLD", /* 0x6450 */ - "JOY", /* 0x6451 */ - "MOD", /* 0x6452 */ - "DIV", /* 0x6453 */ - ">>", /* 0x6454 */ - "DUP", /* 0x6455 */ - "INKEY", /* 0x6456 */ - "INST", /* 0x6457 */ - "TEST", /* 0x6458 */ - "LIN", /* 0x6459 */ - "EXOR", /* 0x645a */ - "INSERT", /* 0x645b */ - "POT", /* 0x645c */ - "PENX", /* 0x645d */ - ">>", /* 0x645e */ - "PENY", /* 0x645f */ - "SOUND", /* 0x6460 */ - "GRAPHICS", /* 0x6461 */ - "DESIGN", /* 0x6462 */ - "RLOCMOB", /* 0x6463 */ - "CMOB", /* 0x6464 */ - "BCKGNDS", /* 0x6465 */ - "PAUSE", /* 0x6466 */ - "NRM", /* 0x6467 */ - "MOB OFF", /* 0x6468 */ - "OFF", /* 0x6469 */ - "ANGL", /* 0x646a */ - "ARC", /* 0x646b */ - "COLD", /* 0x646c */ - "SCRSV", /* 0x646d */ - "SCRLD", /* 0x646e */ - "TEXT", /* 0x646f */ - "CSET", /* 0x6470 */ - "VOL", /* 0x6471 */ - "DISK", /* 0x6472 */ - "HRDCPY", /* 0x6473 */ - "KEY", /* 0x6474 */ - "PAINT", /* 0x6475 */ - "LOW COL", /* 0x6476 */ - "COPY", /* 0x6477 */ - "MERGE", /* 0x6478 */ - "RENUMBER", /* 0x6479 */ - "MEM", /* 0x647a */ - "DETECT", /* 0x647b */ - "CHECK", /* 0x647c */ - "DISPLAY", /* 0x647d */ - "ERR", /* 0x647e */ - "OUT" /* 0x647f */ -}; - -static const char *const basic_20_exp_40[] = /* "BASIC 2.0 with BASIC 4.0 Expansion" - supported by c64 & clones */ -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "NEXT", /* 0x82 */ - "DATA", /* 0x83 */ - "INPUT#", /* 0x84 */ - "INPUT", /* 0x85 */ - "DIM", /* 0x86 */ - "READ", /* 0x87 */ - "LET", /* 0x88 */ - "GOTO", /* 0x89 */ - "RUN", /* 0x8a */ - "IF", /* 0x8b */ - "RESTORE", /* 0x8c */ - "GOSUB", /* 0x8d */ - "RETURN", /* 0x8e */ - "REM", /* 0x8f */ - "STOP", /* 0x90 */ - "ON", /* 0x91 */ - "WAIT", /* 0x92 */ - "LOAD", /* 0x93 */ - "SAVE", /* 0x94 */ - "VERIFY", /* 0x95 */ - "DEF", /* 0x96 */ - "POKE", /* 0x97 */ - "PRINT#", /* 0x98 */ - "PRINT", /* 0x99 */ - "CONT", /* 0x9a */ - "LIST", /* 0x9b */ - "CLR", /* 0x9c */ - "CMD", /* 0x9d */ - "SYS", /* 0x9e */ - "OPEN", /* 0x9f */ - "CLOSE", /* 0xa0 */ - "GET", /* 0xa1 */ - "NEW", /* 0xa2 */ - "TAB(", /* 0xa3 */ - "TO", /* 0xa4 */ - "FN", /* 0xa5 */ - "SPC(", /* 0xa6 */ - "THEN", /* 0xa7 */ - "NOT", /* 0xa8 */ - "STEP", /* 0xa9 */ - "+", /* 0xaa */ - "-", /* 0xab */ - "*", /* 0xac */ - "/", /* 0xad */ - "^", /* 0xae */ - "AND", /* 0xaf */ - "OR", /* 0xb0 */ - ">", /* 0xb1 */ - "=", /* 0xb2 */ - "<", /* 0xb3 */ - "SGN", /* 0xb4 */ - "INT", /* 0xb5 */ - "ABS", /* 0xb6 */ - "USR", /* 0xb7 */ - "FRE", /* 0xb8 */ - "POS", /* 0xb9 */ - "SQR", /* 0xba */ - "RND", /* 0xbb */ - "LOG", /* 0xbc */ - "EXP", /* 0xbd */ - "COS", /* 0xbe */ - "SIN", /* 0xbf */ - "TAN", /* 0xc0 */ - "ATN", /* 0xc1 */ - "PEEK", /* 0xc2 */ - "LEN", /* 0xc3 */ - "STR$", /* 0xc4 */ - "VAL", /* 0xc5 */ - "ASC", /* 0xc6 */ - "CHR$", /* 0xc7 */ - "LEFT$", /* 0xc8 */ - "RIGHT$", /* 0xc9 */ - "MID$", /* 0xca */ - "GO", /* 0xcb */ - "CONCAT", /* 0xcc */ - "DOPEN", /* 0xcd */ - "DCLOSE", /* 0xce */ - "RECORD", /* 0xcf */ - "HEADER", /* 0xd0 */ - "COLLECT", /* 0xd1 */ - "BACKUP", /* 0xd2 */ - "COPY", /* 0xd3 */ - "APPEND", /* 0xd4 */ - "DSAVE", /* 0xd5 */ - "DLOAD", /* 0xd6 */ - "CATALOG", /* 0xd7 */ - "RENAME", /* 0xd8 */ - "SCRATCH", /* 0xd9 */ - "DIRECTORY", /* 0xda */ - "COLOR", /* 0xdb */ - "COLD", /* 0xdc */ - "KEY", /* 0xdd */ - "DVERIFY", /* 0xde */ - "DELETE" /* 0xdf */ - "AUTO", /* 0xe0 */ - "MERGE", /* 0xe1 */ - "OLD", /* 0xe2 */ - "MONITOR", /* 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 */ - "{PI}" /* 0xff - A single character shaped as greek lowercase 'PI' */ -}; - -static const char *const basic_35[] = /* "BASIC 3.5" - supported by c16 & clones, except c364 */ -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "NEXT", /* 0x82 */ - "DATA", /* 0x83 */ - "INPUT#", /* 0x84 */ - "INPUT", /* 0x85 */ - "DIM", /* 0x86 */ - "READ", /* 0x87 */ - "LET", /* 0x88 */ - "GOTO", /* 0x89 */ - "RUN", /* 0x8a */ - "IF", /* 0x8b */ - "RESTORE", /* 0x8c */ - "GOSUB", /* 0x8d */ - "RETURN", /* 0x8e */ - "REM", /* 0x8f */ - "STOP", /* 0x90 */ - "ON", /* 0x91 */ - "WAIT", /* 0x92 */ - "LOAD", /* 0x93 */ - "SAVE", /* 0x94 */ - "VERIFY", /* 0x95 */ - "DEF", /* 0x96 */ - "POKE", /* 0x97 */ - "PRINT#", /* 0x98 */ - "PRINT", /* 0x99 */ - "CONT", /* 0x9a */ - "LIST", /* 0x9b */ - "CLR", /* 0x9c */ - "CMD", /* 0x9d */ - "SYS", /* 0x9e */ - "OPEN", /* 0x9f */ - "CLOSE", /* 0xa0 */ - "GET", /* 0xa1 */ - "NEW", /* 0xa2 */ - "TAB(", /* 0xa3 */ - "TO", /* 0xa4 */ - "FN", /* 0xa5 */ - "SPC(", /* 0xa6 */ - "THEN", /* 0xa7 */ - "NOT", /* 0xa8 */ - "STEP", /* 0xa9 */ - "+", /* 0xaa */ - "-", /* 0xab */ - "*", /* 0xac */ - "/", /* 0xad */ - "^", /* 0xae */ - "AND", /* 0xaf */ - "OR", /* 0xb0 */ - ">", /* 0xb1 */ - "=", /* 0xb2 */ - "<", /* 0xb3 */ - "SGN", /* 0xb4 */ - "INT", /* 0xb5 */ - "ABS", /* 0xb6 */ - "USR", /* 0xb7 */ - "FRE", /* 0xb8 */ - "POS", /* 0xb9 */ - "SQR", /* 0xba */ - "RND", /* 0xbb */ - "LOG", /* 0xbc */ - "EXP", /* 0xbd */ - "COS", /* 0xbe */ - "SIN", /* 0xbf */ - "TAN", /* 0xc0 */ - "ATN", /* 0xc1 */ - "PEEK", /* 0xc2 */ - "LEN", /* 0xc3 */ - "STR$", /* 0xc4 */ - "VAL", /* 0xc5 */ - "ASC", /* 0xc6 */ - "CHR$", /* 0xc7 */ - "LEFT$", /* 0xc8 */ - "RIGHT$", /* 0xc9 */ - "MID$", /* 0xca */ - "GO", /* 0xcb */ - "RGR", /* 0xcc */ - "RCLR" /* 0xcd */ - "RLUM" /* 0xce */ - "JOY", /* 0xcf */ - "RDOT" /* 0xd0 */ - "DEC", /* 0xd1 */ - "HEX$", /* 0xd2 */ - "ERR$", /* 0xd3 */ - "INSTR", /* 0xd4 */ - "ELSE", /* 0xd5 */ - "RESUME", /* 0xd6 */ - "TRAP", /* 0xd7 */ - "TRON", /* 0xd8 */ - "TROFF", /* 0xd9 */ - "SOUND", /* 0xda */ - "VOL", /* 0xdb */ - "AUTO", /* 0xdc */ - "PUDEF", /* 0xdd */ - "GRAPHIC", /* 0xde */ - "PAINT", /* 0xdf */ - "CHAR", /* 0xe0 */ - "BOX", /* 0xe1 */ - "CIRCLE", /* 0xe2 */ - "GSHAPE", /* 0xe3 */ - "SSHAPE", /* 0xe4 */ - "DRAW", /* 0xe5 */ - "LOCATE", /* 0xe6 */ - "COLOR", /* 0xe7 */ - "SCNCLR", /* 0xe8 */ - "SCALE", /* 0xe9 */ - "HELP", /* 0xea */ - "DO", /* 0xeb */ - "LOOP", /* 0xec */ - "EXIT", /* 0xed */ - "DIRECTORY", /* 0xee */ - "DSAVE", /* 0xef */ - "DLOAD", /* 0xf0 */ - "HEADER", /* 0xf1 */ - "SCRATCH", /* 0xf2 */ - "COLLECT", /* 0xf3 */ - "COPY", /* 0xf4 */ - "RENAME", /* 0xf5 */ - "BACKUP", /* 0xf6 */ - "DELETE", /* 0xf7 */ - "RENUMBER", /* 0xf8 */ - "KEY", /* 0xf9 */ - "MONITOR", /* 0xfa */ - "USING", /* 0xfb */ - "UNTIL", /* 0xfc */ - "WHILE", /* 0xfd */ - NULL, /* 0xfe */ - "{PI}" /* 0xff - A single character shaped as greek lowercase 'PI' */ -}; - -static const char *const basic_35_magic_voice[] = /* "BASIC 3.5 with Magic Voice Speech Synthesizer" - supported by c364 */ -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "NEXT", /* 0x82 */ - "DATA", /* 0x83 */ - "INPUT#", /* 0x84 */ - "INPUT", /* 0x85 */ - "DIM", /* 0x86 */ - "READ", /* 0x87 */ - "LET", /* 0x88 */ - "GOTO", /* 0x89 */ - "RUN", /* 0x8a */ - "IF", /* 0x8b */ - "RESTORE", /* 0x8c */ - "GOSUB", /* 0x8d */ - "RETURN", /* 0x8e */ - "REM", /* 0x8f */ - "STOP", /* 0x90 */ - "ON", /* 0x91 */ - "WAIT", /* 0x92 */ - "LOAD", /* 0x93 */ - "SAVE", /* 0x94 */ - "VERIFY", /* 0x95 */ - "DEF", /* 0x96 */ - "POKE", /* 0x97 */ - "PRINT#", /* 0x98 */ - "PRINT", /* 0x99 */ - "CONT", /* 0x9a */ - "LIST", /* 0x9b */ - "CLR", /* 0x9c */ - "CMD", /* 0x9d */ - "SYS", /* 0x9e */ - "OPEN", /* 0x9f */ - "CLOSE", /* 0xa0 */ - "GET", /* 0xa1 */ - "NEW", /* 0xa2 */ - "TAB(", /* 0xa3 */ - "TO", /* 0xa4 */ - "FN", /* 0xa5 */ - "SPC(", /* 0xa6 */ - "THEN", /* 0xa7 */ - "NOT", /* 0xa8 */ - "STEP", /* 0xa9 */ - "+", /* 0xaa */ - "-", /* 0xab */ - "*", /* 0xac */ - "/", /* 0xad */ - "^", /* 0xae */ - "AND", /* 0xaf */ - "OR", /* 0xb0 */ - ">", /* 0xb1 */ - "=", /* 0xb2 */ - "<", /* 0xb3 */ - "SGN", /* 0xb4 */ - "INT", /* 0xb5 */ - "ABS", /* 0xb6 */ - "USR", /* 0xb7 */ - "FRE", /* 0xb8 */ - "POS", /* 0xb9 */ - "SQR", /* 0xba */ - "RND", /* 0xbb */ - "LOG", /* 0xbc */ - "EXP", /* 0xbd */ - "COS", /* 0xbe */ - "SIN", /* 0xbf */ - "TAN", /* 0xc0 */ - "ATN", /* 0xc1 */ - "PEEK", /* 0xc2 */ - "LEN", /* 0xc3 */ - "STR$", /* 0xc4 */ - "VAL", /* 0xc5 */ - "ASC", /* 0xc6 */ - "CHR$", /* 0xc7 */ - "LEFT$", /* 0xc8 */ - "RIGHT$", /* 0xc9 */ - "MID$", /* 0xca */ - "GO", /* 0xcb */ - "RGR", /* 0xcc */ - "RCLR" /* 0xcd */ - "RLUM" /* 0xce */ - "JOY", /* 0xcf */ - "RDOT" /* 0xd0 */ - "DEC", /* 0xd1 */ - "HEX$", /* 0xd2 */ - "ERR$", /* 0xd3 */ - "INSTR", /* 0xd4 */ - "ELSE", /* 0xd5 */ - "RESUME", /* 0xd6 */ - "TRAP", /* 0xd7 */ - "TRON", /* 0xd8 */ - "TROFF", /* 0xd9 */ - "SOUND", /* 0xda */ - "VOL", /* 0xdb */ - "AUTO", /* 0xdc */ - "PUDEF", /* 0xdd */ - "GRAPHIC", /* 0xde */ - "PAINT", /* 0xdf */ - "CHAR", /* 0xe0 */ - "BOX", /* 0xe1 */ - "CIRCLE", /* 0xe2 */ - "GSHAPE", /* 0xe3 */ - "SSHAPE", /* 0xe4 */ - "DRAW", /* 0xe5 */ - "LOCATE", /* 0xe6 */ - "COLOR", /* 0xe7 */ - "SCNCLR", /* 0xe8 */ - "SCALE", /* 0xe9 */ - "HELP", /* 0xea */ - "DO", /* 0xeb */ - "LOOP", /* 0xec */ - "EXIT", /* 0xed */ - "DIRECTORY", /* 0xee */ - "DSAVE", /* 0xef */ - "DLOAD", /* 0xf0 */ - "HEADER", /* 0xf1 */ - "SCRATCH", /* 0xf2 */ - "COLLECT", /* 0xf3 */ - "COPY", /* 0xf4 */ - "RENAME", /* 0xf5 */ - "BACKUP", /* 0xf6 */ - "DELETE", /* 0xf7 */ - "RENUMBER", /* 0xf8 */ - "KEY", /* 0xf9 */ - "MONITOR", /* 0xfa */ - "USING", /* 0xfb */ - "UNTIL", /* 0xfc */ - "WHILE", /* 0xfd */ - NULL, /* 0xfe - Prefix for additional tokens */ - "{PI}", /* 0xff - A single character shaped as greek lowercase 'PI' */ - NULL, /* 0xfe00 */ - "RATE", /* 0xfe01 */ - "VOC", /* 0xfe02 */ - NULL, /* 0xfe03 */ - "RDY", /* 0xfe04 */ - NULL, /* 0xfe05 */ - NULL, /* 0xfe06 */ - NULL, /* 0xfe07 */ - NULL, /* 0xfe08 */ - NULL, /* 0xfe09 */ - "SAY" /* 0xfe0a */ -}; - -static const char *const basic_40[] = /* "BASIC 4.0" - supported by cbm40xx & cbm80xx series, p500, cbm600 & clones */ -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "NEXT", /* 0x82 */ - "DATA", /* 0x83 */ - "INPUT#", /* 0x84 */ - "INPUT", /* 0x85 */ - "DIM", /* 0x86 */ - "READ", /* 0x87 */ - "LET", /* 0x88 */ - "GOTO", /* 0x89 */ - "RUN", /* 0x8a */ - "IF", /* 0x8b */ - "RESTORE", /* 0x8c */ - "GOSUB", /* 0x8d */ - "RETURN", /* 0x8e */ - "REM", /* 0x8f */ - "STOP", /* 0x90 */ - "ON", /* 0x91 */ - "WAIT", /* 0x92 */ - "LOAD", /* 0x93 */ - "SAVE", /* 0x94 */ - "VERIFY", /* 0x95 */ - "DEF", /* 0x96 */ - "POKE", /* 0x97 */ - "PRINT#", /* 0x98 */ - "PRINT", /* 0x99 */ - "CONT", /* 0x9a */ - "LIST", /* 0x9b */ - "CLR", /* 0x9c */ - "CMD", /* 0x9d */ - "SYS", /* 0x9e */ - "OPEN", /* 0x9f */ - "CLOSE", /* 0xa0 */ - "GET", /* 0xa1 */ - "NEW", /* 0xa2 */ - "TAB(", /* 0xa3 */ - "TO", /* 0xa4 */ - "FN", /* 0xa5 */ - "SPC(", /* 0xa6 */ - "THEN", /* 0xa7 */ - "NOT", /* 0xa8 */ - "STEP", /* 0xa9 */ - "+", /* 0xaa */ - "-", /* 0xab */ - "*", /* 0xac */ - "/", /* 0xad */ - "^", /* 0xae */ - "AND", /* 0xaf */ - "OR", /* 0xb0 */ - ">", /* 0xb1 */ - "=", /* 0xb2 */ - "<", /* 0xb3 */ - "SGN", /* 0xb4 */ - "INT", /* 0xb5 */ - "ABS", /* 0xb6 */ - "USR", /* 0xb7 */ - "FRE", /* 0xb8 */ - "POS", /* 0xb9 */ - "SQR", /* 0xba */ - "RND", /* 0xbb */ - "LOG", /* 0xbc */ - "EXP", /* 0xbd */ - "COS", /* 0xbe */ - "SIN", /* 0xbf */ - "TAN", /* 0xc0 */ - "ATN", /* 0xc1 */ - "PEEK", /* 0xc2 */ - "LEN", /* 0xc3 */ - "STR$", /* 0xc4 */ - "VAL", /* 0xc5 */ - "ASC", /* 0xc6 */ - "CHR$", /* 0xc7 */ - "LEFT$", /* 0xc8 */ - "RIGHT$", /* 0xc9 */ - "MID$", /* 0xca */ - "GO", /* 0xcb */ - "CONCAT", /* 0xcc */ - "DOPEN", /* 0xcd */ - "DCLOSE", /* 0xce */ - "RECORD", /* 0xcf */ - "HEADER", /* 0xd0 */ - "COLLECT", /* 0xd1 */ - "BACKUP", /* 0xd2 */ - "COPY", /* 0xd3 */ - "APPEND", /* 0xd4 */ - "DSAVE", /* 0xd5 */ - "DLOAD", /* 0xd6 */ - "CATALOG", /* 0xd7 */ - "RENAME", /* 0xd8 */ - "SCRATCH", /* 0xd9 */ - "DIRECTORY", /* 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 */ - "{PI}" /* 0xff - A single character shaped as greek lowercase 'PI' */ -}; - -static const char *const basic_70[] = /* "BASIC 7.0" - supported by c128 & clones */ -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "NEXT", /* 0x82 */ - "DATA", /* 0x83 */ - "INPUT#", /* 0x84 */ - "INPUT", /* 0x85 */ - "DIM", /* 0x86 */ - "READ", /* 0x87 */ - "LET", /* 0x88 */ - "GOTO", /* 0x89 */ - "RUN", /* 0x8a */ - "IF", /* 0x8b */ - "RESTORE", /* 0x8c */ - "GOSUB", /* 0x8d */ - "RETURN", /* 0x8e */ - "REM", /* 0x8f */ - "STOP", /* 0x90 */ - "ON", /* 0x91 */ - "WAIT", /* 0x92 */ - "LOAD", /* 0x93 */ - "SAVE", /* 0x94 */ - "VERIFY", /* 0x95 */ - "DEF", /* 0x96 */ - "POKE", /* 0x97 */ - "PRINT#", /* 0x98 */ - "PRINT", /* 0x99 */ - "CONT", /* 0x9a */ - "LIST", /* 0x9b */ - "CLR", /* 0x9c */ - "CMD", /* 0x9d */ - "SYS", /* 0x9e */ - "OPEN", /* 0x9f */ - "CLOSE", /* 0xa0 */ - "GET", /* 0xa1 */ - "NEW", /* 0xa2 */ - "TAB(", /* 0xa3 */ - "TO", /* 0xa4 */ - "FN", /* 0xa5 */ - "SPC(", /* 0xa6 */ - "THEN", /* 0xa7 */ - "NOT", /* 0xa8 */ - "STEP", /* 0xa9 */ - "+", /* 0xaa */ - "-", /* 0xab */ - "*", /* 0xac */ - "/", /* 0xad */ - "^", /* 0xae */ - "AND", /* 0xaf */ - "OR", /* 0xb0 */ - ">", /* 0xb1 */ - "=", /* 0xb2 */ - "<", /* 0xb3 */ - "SGN", /* 0xb4 */ - "INT", /* 0xb5 */ - "ABS", /* 0xb6 */ - "USR", /* 0xb7 */ - "FRE", /* 0xb8 */ - "POS", /* 0xb9 */ - "SQR", /* 0xba */ - "RND", /* 0xbb */ - "LOG", /* 0xbc */ - "EXP", /* 0xbd */ - "COS", /* 0xbe */ - "SIN", /* 0xbf */ - "TAN", /* 0xc0 */ - "ATN", /* 0xc1 */ - "PEEK", /* 0xc2 */ - "LEN", /* 0xc3 */ - "STR$", /* 0xc4 */ - "VAL", /* 0xc5 */ - "ASC", /* 0xc6 */ - "CHR$", /* 0xc7 */ - "LEFT$", /* 0xc8 */ - "RIGHT$", /* 0xc9 */ - "MID$", /* 0xca */ - "GO", /* 0xcb */ - "RGR", /* 0xcc */ - "RCLR", /* 0xcd */ - NULL, /* 0xce - Prefix for additional tokens */ - "JOY", /* 0xcf */ - "RDOT" /* 0xd0 */ - "DEC", /* 0xd1 */ - "HEX$", /* 0xd2 */ - "ERR$", /* 0xd3 */ - "INSTR", /* 0xd4 */ - "ELSE", /* 0xd5 */ - "RESUME", /* 0xd6 */ - "TRAP", /* 0xd7 */ - "TRON", /* 0xd8 */ - "TROFF", /* 0xd9 */ - "SOUND", /* 0xda */ - "VOL", /* 0xdb */ - "AUTO", /* 0xdc */ - "PUDEF", /* 0xdd */ - "GRAPHIC", /* 0xde */ - "PAINT", /* 0xdf */ - "CHAR", /* 0xe0 */ - "BOX", /* 0xe1 */ - "CIRCLE", /* 0xe2 */ - "GSHAPE", /* 0xe3 */ - "SSHAPE", /* 0xe4 */ - "DRAW", /* 0xe5 */ - "LOCATE", /* 0xe6 */ - "COLOR", /* 0xe7 */ - "SCNCLR", /* 0xe8 */ - "SCALE", /* 0xe9 */ - "HELP", /* 0xea */ - "DO", /* 0xeb */ - "LOOP", /* 0xec */ - "EXIT", /* 0xed */ - "DIRECTORY", /* 0xee */ - "DSAVE", /* 0xef */ - "DLOAD", /* 0xf0 */ - "HEADER", /* 0xf1 */ - "SCRATCH", /* 0xf2 */ - "COLLECT", /* 0xf3 */ - "COPY", /* 0xf4 */ - "RENAME", /* 0xf5 */ - "BACKUP", /* 0xf6 */ - "DELETE", /* 0xf7 */ - "RENUMBER", /* 0xf8 */ - "KEY", /* 0xf9 */ - "MONITOR", /* 0xfa */ - "USING", /* 0xfb */ - "UNTIL", /* 0xfc */ - "WHILE", /* 0xfd */ - NULL, /* 0xfe - Prefix for additional tokens */ - "{PI}", /* 0xff - A single character shaped as greek lowercase 'PI' */ - NULL, /* 0xce00 */ - NULL, /* 0xce01 */ - "POT", /* 0xce02 */ - "BUMP", /* 0xce03 */ - "PEN", /* 0xce04 */ - "RSPPOS", /* 0xce05 */ - "RSPRITE", /* 0xce06 */ - "RSPCOLOR", /* 0xce07 */ - "XOR", /* 0xce08 */ - "RWINDOW", /* 0xce09 */ - "POINTER", /* 0xce0a */ - NULL, /* 0xfe00 */ - NULL, /* 0xfe01 */ - "BANK", /* 0xfe02 */ - "FILTER", /* 0xfe03 */ - "PLAY", /* 0xfe04 */ - "TEMPO", /* 0xfe05 */ - "MOVSPR", /* 0xfe06 */ - "SPRITE", /* 0xfe07 */ - "SPRCOLOR", /* 0xfe08 */ - "RREG", /* 0xfe09 */ - "ENVELOPE", /* 0xfe0a */ - "SLEEP", /* 0xfe0b */ - "CATALOG", /* 0xfe0c */ - "DOPEN", /* 0xfe0d */ - "APPEND", /* 0xfe0e */ - "DCLOSE", /* 0xfe0f */ - "BSAVE", /* 0xfe10 */ - "BLOAD", /* 0xfe11 */ - "RECORD", /* 0xfe12 */ - "CONCAT", /* 0xfe13 */ - "DVERIFY", /* 0xfe14 */ - "DCLEAR", /* 0xfe15 */ - "SPRSAV", /* 0xfe16 */ - "COLLISION", /* 0xfe17 */ - "BEGIN", /* 0xfe18 */ - "BEND", /* 0xfe19 */ - "WINDOW", /* 0xfe1a */ - "BOOT", /* 0xfe1b */ - "WIDTH", /* 0xfe1c */ - "SPRDEF", /* 0xfe1d */ - "QUIT", /* 0xfe1e */ - "STASH", /* 0xfe1f */ - NULL, /* 0xfe20 */ - "FETCH", /* 0xfe21 */ - NULL, /* 0xfe22 */ - "SWAP", /* 0xfe23 */ - "OFF", /* 0xfe24 */ - "FAST", /* 0xfe25 */ - "SLOW" /* 0xfe26 */ -}; - -static const char *const basic_100[] = /* "BASIC 10.0" - supported by c65 & clones */ -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "NEXT", /* 0x82 */ - "DATA", /* 0x83 */ - "INPUT#", /* 0x84 */ - "INPUT", /* 0x85 */ - "DIM", /* 0x86 */ - "READ", /* 0x87 */ - "LET", /* 0x88 */ - "GOTO", /* 0x89 */ - "RUN", /* 0x8a */ - "IF", /* 0x8b */ - "RESTORE", /* 0x8c */ - "GOSUB", /* 0x8d */ - "RETURN", /* 0x8e */ - "REM", /* 0x8f */ - "STOP", /* 0x90 */ - "ON", /* 0x91 */ - "WAIT", /* 0x92 */ - "LOAD", /* 0x93 */ - "SAVE", /* 0x94 */ - "VERIFY", /* 0x95 */ - "DEF", /* 0x96 */ - "POKE", /* 0x97 */ - "PRINT#", /* 0x98 */ - "PRINT", /* 0x99 */ - "CONT", /* 0x9a */ - "LIST", /* 0x9b */ - "CLR", /* 0x9c */ - "CMD", /* 0x9d */ - "SYS", /* 0x9e */ - "OPEN", /* 0x9f */ - "CLOSE", /* 0xa0 */ - "GET", /* 0xa1 */ - "NEW", /* 0xa2 */ - "TAB(", /* 0xa3 */ - "TO", /* 0xa4 */ - "FN", /* 0xa5 */ - "SPC(", /* 0xa6 */ - "THEN", /* 0xa7 */ - "NOT", /* 0xa8 */ - "STEP", /* 0xa9 */ - "+", /* 0xaa */ - "-", /* 0xab */ - "*", /* 0xac */ - "/", /* 0xad */ - "^", /* 0xae */ - "AND", /* 0xaf */ - "OR", /* 0xb0 */ - ">", /* 0xb1 */ - "=", /* 0xb2 */ - "<", /* 0xb3 */ - "SGN", /* 0xb4 */ - "INT", /* 0xb5 */ - "ABS", /* 0xb6 */ - "USR", /* 0xb7 */ - "FRE", /* 0xb8 */ - "POS", /* 0xb9 */ - "SQR", /* 0xba */ - "RND", /* 0xbb */ - "LOG", /* 0xbc */ - "EXP", /* 0xbd */ - "COS", /* 0xbe */ - "SIN", /* 0xbf */ - "TAN", /* 0xc0 */ - "ATN", /* 0xc1 */ - "PEEK", /* 0xc2 */ - "LEN", /* 0xc3 */ - "STR$", /* 0xc4 */ - "VAL", /* 0xc5 */ - "ASC", /* 0xc6 */ - "CHR$", /* 0xc7 */ - "LEFT$", /* 0xc8 */ - "RIGHT$", /* 0xc9 */ - "MID$", /* 0xca */ - "GO", /* 0xcb */ - "RGR", /* 0xcc */ - "RCLR", /* 0xcd */ - NULL, /* 0xce - Prefix for additional tokens */ - "JOY", /* 0xcf */ - "RDOT" /* 0xd0 */ - "DEC", /* 0xd1 */ - "HEX$", /* 0xd2 */ - "ERR$", /* 0xd3 */ - "INSTR", /* 0xd4 */ - "ELSE", /* 0xd5 */ - "RESUME", /* 0xd6 */ - "TRAP", /* 0xd7 */ - "TRON", /* 0xd8 */ - "TROFF", /* 0xd9 */ - "SOUND", /* 0xda */ - "VOL", /* 0xdb */ - "AUTO", /* 0xdc */ - "PUDEF", /* 0xdd */ - "GRAPHIC", /* 0xde */ - "PAINT", /* 0xdf */ - "CHAR", /* 0xe0 */ - "BOX", /* 0xe1 */ - "CIRCLE", /* 0xe2 */ - "PASTE", /* 0xe3 */ - "CUT", /* 0xe4 */ - "LINE", /* 0xe5 */ - "LOCATE", /* 0xe6 */ - "COLOR", /* 0xe7 */ - "SCNCLR", /* 0xe8 */ - "SCALE", /* 0xe9 */ - "HELP", /* 0xea */ - "DO", /* 0xeb */ - "LOOP", /* 0xec */ - "EXIT", /* 0xed */ - "DIR", /* 0xee */ - "DSAVE", /* 0xef */ - "DLOAD", /* 0xf0 */ - "HEADER", /* 0xf1 */ - "SCRATCH", /* 0xf2 */ - "COLLECT", /* 0xf3 */ - "COPY", /* 0xf4 */ - "RENAME", /* 0xf5 */ - "BACKUP", /* 0xf6 */ - "DELETE", /* 0xf7 */ - "RENUMBER", /* 0xf8 */ - "KEY", /* 0xf9 */ - "MONITOR", /* 0xfa */ - "USING", /* 0xfb */ - "UNTIL", /* 0xfc */ - "WHILE", /* 0xfd */ - NULL, /* 0xfe - Prefix for additional tokens */ - "{PI}", /* 0xff - A single character shaped as greek lowercase 'PI' */ - NULL, /* 0xce00 */ - NULL, /* 0xce01 */ - "POT", /* 0xce02 */ - "BUMP", /* 0xce03 */ - "PEN", /* 0xce04 */ - "RSPPOS", /* 0xce05 */ - "RSPRITE", /* 0xce06 */ - "RSPCOLOR", /* 0xce07 */ - "XOR", /* 0xce08 */ - "RWINDOW", /* 0xce09 */ - "POINTER", /* 0xce0a */ - NULL, /* 0xfe00 */ - NULL, /* 0xfe01 */ - "BANK", /* 0xfe02 */ - "FILTER", /* 0xfe03 */ - "PLAY", /* 0xfe04 */ - "TEMPO", /* 0xfe05 */ - "MOVSPR", /* 0xfe06 */ - "SPRITE", /* 0xfe07 */ - "SPRCOLOR", /* 0xfe08 */ - "RREG", /* 0xfe09 */ - "ENVELOPE", /* 0xfe0a */ - "SLEEP", /* 0xfe0b */ - "CATALOG", /* 0xfe0c */ - "DOPEN", /* 0xfe0d */ - "APPEND", /* 0xfe0e */ - "DCLOSE", /* 0xfe0f */ - "BSAVE", /* 0xfe10 */ - "BLOAD", /* 0xfe11 */ - "RECORD", /* 0xfe12 */ - "CONCAT", /* 0xfe13 */ - "DVERIFY", /* 0xfe14 */ - "DCLEAR", /* 0xfe15 */ - "SPRSAV", /* 0xfe16 */ - "COLLISION", /* 0xfe17 */ - "BEGIN", /* 0xfe18 */ - "BEND", /* 0xfe19 */ - "WINDOW", /* 0xfe1a */ - "BOOT", /* 0xfe1b */ - "WIDTH", /* 0xfe1c */ - "SPRDEF", /* 0xfe1d */ - "QUIT", /* 0xfe1e */ - "DMA", /* 0xfe1f */ - NULL, /* 0xfe20 */ - "DMA", /* 0xfe21 */ - NULL, /* 0xfe22 */ - "DMA", /* 0xfe23 */ - "OFF", /* 0xfe24 */ - "FAST", /* 0xfe25 */ - "SLOW", /* 0xfe26 */ - "TYPE", /* 0xfe27 */ - "BVERIFY", /* 0xfe28 */ - "ECTORY", /* 0xfe29 */ - "ERASE", /* 0xfe2a */ - "FIND", /* 0xfe2b */ - "CHANGE", /* 0xfe2c */ - "SET", /* 0xfe2d */ - "SCREEN", /* 0xfe2e */ - "POLYGON", /* 0xfe2f */ - "ELLIPSE", /* 0xfe30 */ - "VIEWPORT", /* 0xfe31 */ - "GCOPY", /* 0xfe32 */ - "PEN", /* 0xfe33 */ - "PALETTE", /* 0xfe34 */ - "DMODE", /* 0xfe35 */ - "DPAT", /* 0xfe36 */ - "PIC", /* 0xfe37 */ - "GENLOCK", /* 0xfe38 */ - "FOREGROUND", /* 0xfe39 */ - NULL, /* 0xfe3a */ - "BACKGROUND", /* 0xfe3b */ - "BORDER", /* 0xfe3c */ - "HIGHLIGHT" /* 0xfe3d */ -}; - -#endif - - - -/*************************************************************************** - COCO BASIC -***************************************************************************/ - -static const basictoken_tableent cocobas_tokenents[] = -{ - { 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, - std::size(cocobas_tokenents) -}; - -static imgtoolerr_t cocobas_readfile(imgtool::partition &partition, const char *filename, - const char *fork, imgtool::stream &destf) -{ - return basic_readfile(&cocobas_tokens, partition, filename, fork, destf); -} - -static imgtoolerr_t cocobas_writefile(imgtool::partition &partition, const char *filename, - const char *fork, imgtool::stream &sourcef, util::option_resolution *opts) -{ - return basic_writefile(&cocobas_tokens, partition, filename, fork, sourcef, opts); -} - -void filter_cocobas_getinfo(uint32_t state, union filterinfo *info) -{ - switch(state) - { - case FILTINFO_STR_NAME: info->s = "cocobas"; break; - case FILTINFO_STR_HUMANNAME: info->s = "CoCo Tokenized Basic Files"; break; - case FILTINFO_PTR_READFILE: info->read_file = cocobas_readfile; break; - case FILTINFO_PTR_WRITEFILE: info->write_file = cocobas_writefile; break; - } -} - - - -/*************************************************************************** - DRAGON BASIC -***************************************************************************/ - -static const basictoken_tableent dragonbas_tokenents[] = -{ - { 0x00, 0x80, dragonbas_statements, std::size(dragonbas_statements) }, - { 0xff, 0x80, dragonbas_functions, std::size(dragonbas_functions) } -}; - -static const basictokens dragonbas_tokens = -{ - 0x2415, - 4, - 9, - {0x55, 0x01, 0x24, 0x01, 0x00, 0x2A, 0x8B, 0x8D, 0xAA}, - true, - dragonbas_tokenents, - std::size(dragonbas_tokenents) -}; - -static imgtoolerr_t dragonbas_readfile(imgtool::partition &partition, const char *filename, - const char *fork, imgtool::stream &destf) -{ - return basic_readfile(&dragonbas_tokens, partition, filename, fork, destf); -} - -static imgtoolerr_t dragonbas_writefile(imgtool::partition &partition, const char *filename, - const char *fork, imgtool::stream &sourcef, util::option_resolution *opts) -{ - return basic_writefile(&dragonbas_tokens, partition, filename, fork, sourcef, opts); -} - -void filter_dragonbas_getinfo(uint32_t state, union filterinfo *info) -{ - switch(state) - { - case FILTINFO_STR_NAME: info->s = "dragonbas"; break; - case FILTINFO_STR_HUMANNAME: info->s = "Dragon Tokenized Basic Files"; break; - case FILTINFO_PTR_READFILE: info->read_file = dragonbas_readfile; break; - case FILTINFO_PTR_WRITEFILE: info->write_file = dragonbas_writefile; break; - } -} - - - -/*************************************************************************** - VZBASIC -***************************************************************************/ - -static const basictoken_tableent vzbas_tokenents[] = -{ - { 0x00, 0x80, vzbas, std::size(vzbas) } -}; - - - -static const basictokens vzbas_tokens = -{ - 0x7ae9, - 0, - 0, - {0x00}, - false, - vzbas_tokenents, - std::size(vzbas_tokenents) -}; - -static imgtoolerr_t vzbas_readfile(imgtool::partition &partition, const char *filename, - const char *fork, imgtool::stream &destf) -{ - return basic_readfile(&vzbas_tokens, partition, filename, fork, destf); -} - -static imgtoolerr_t vzbas_writefile(imgtool::partition &partition, const char *filename, - const char *fork, imgtool::stream &sourcef, util::option_resolution *opts) -{ - return basic_writefile(&vzbas_tokens, partition, filename, fork, sourcef, opts); -} - -void filter_vzbas_getinfo(uint32_t state, union filterinfo *info) -{ - switch(state) - { - case FILTINFO_STR_NAME: info->s = "vzbas"; break; - case FILTINFO_STR_HUMANNAME: info->s = "Laser/VZ Tokenized Basic Files"; break; - case FILTINFO_PTR_READFILE: info->read_file = vzbas_readfile; break; - case FILTINFO_PTR_WRITEFILE: info->write_file = vzbas_writefile; break; - } -} - - - -/*************************************************************************** - BML3 BASIC -***************************************************************************/ - -static const basictoken_tableent bml3bas_tokenents[] = -{ - { 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, - std::size(bml3bas_tokenents) -}; - -static imgtoolerr_t bml3bas_readfile(imgtool::partition &partition, const char *filename, - const char *fork, imgtool::stream &destf) -{ - return basic_readfile(&bml3bas_tokens, partition, filename, fork, destf); -} - -static imgtoolerr_t bml3bas_writefile(imgtool::partition &partition, const char *filename, - const char *fork, imgtool::stream &sourcef, util::option_resolution *opts) -{ - return basic_writefile(&bml3bas_tokens, partition, filename, fork, sourcef, opts); -} - -void filter_bml3bas_getinfo(uint32_t state, union filterinfo *info) -{ - switch(state) - { - case FILTINFO_STR_NAME: info->s = "bml3bas"; break; - case FILTINFO_STR_HUMANNAME: info->s = "Basic Master Level 3 Tokenized Basic Files"; break; - case FILTINFO_PTR_READFILE: info->read_file = bml3bas_readfile; break; - case FILTINFO_PTR_WRITEFILE: info->write_file = bml3bas_writefile; break; - } -} diff --git a/src/tools/imgtool/filteoln.cpp b/src/tools/imgtool/filteoln.cpp deleted file mode 100644 index 6d80e9b..0000000 --- a/src/tools/imgtool/filteoln.cpp +++ /dev/null @@ -1,108 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/**************************************************************************** - - filteoln.c - - Native end-of-line filter - -*****************************************************************************/ - -#include "imgtool.h" -#include "filter.h" - -#include - -#define EOLN (CRLF == 1 ? "\r" : (CRLF == 2 ? "\n" : (CRLF == 3 ? "\r\n" : NULL))) - - - -static imgtoolerr_t convert_stream_eolns(imgtool::stream &source, imgtool::stream &dest, const char *eoln) -{ - size_t len, i, pos; - char buffer[2000]; - int hit_cr = false; - - while((len = source.read(buffer, sizeof(buffer))) > 0) - { - pos = 0; - - for (i = 0; i < len; i++) - { - switch(buffer[i]) - { - case '\r': - case '\n': - if (!hit_cr || (buffer[i] != '\n')) - { - if (i > pos) - dest.write(buffer + pos, i - pos); - dest.write(eoln, strlen(eoln)); - } - pos = i + 1; - break; - } - hit_cr = (buffer[i] == '\r'); - } - - if (i > pos) - dest.write(buffer + pos, i - pos); - } - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t ascii_readfile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &destf) -{ - imgtoolerr_t err; - imgtool::stream::ptr mem_stream; - - mem_stream = imgtool::stream::open_mem(nullptr, 0); - if (!mem_stream) - return IMGTOOLERR_OUTOFMEMORY; - - err = partition.read_file(filename, fork, *mem_stream, nullptr); - if (err) - return err; - - mem_stream->seek(SEEK_SET, 0); - return convert_stream_eolns(*mem_stream, destf, EOLN); -} - - - -static imgtoolerr_t ascii_writefile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &sourcef, util::option_resolution *opts) -{ - imgtoolerr_t err; - imgtool::stream::ptr mem_stream; - const char *eoln; - - /* create a stream */ - mem_stream = imgtool::stream::open_mem(nullptr, 0); - if (!mem_stream) - return IMGTOOLERR_OUTOFMEMORY; - - eoln = partition.get_info_string(IMGTOOLINFO_STR_EOLN); - - err = convert_stream_eolns(sourcef, *mem_stream, eoln); - if (err) - return err; - mem_stream->seek(SEEK_SET, 0); - - return partition.write_file(filename, fork, *mem_stream, opts, nullptr); -} - - - -void filter_eoln_getinfo(uint32_t state, union filterinfo *info) -{ - switch(state) - { - case FILTINFO_STR_NAME: info->s = "ascii"; break; - case FILTINFO_STR_HUMANNAME: info->s = "Ascii"; break; - case FILTINFO_PTR_READFILE: info->read_file = ascii_readfile; break; - case FILTINFO_PTR_WRITEFILE: info->write_file = ascii_writefile; break; - } -} diff --git a/src/tools/imgtool/filter.cpp b/src/tools/imgtool/filter.cpp deleted file mode 100644 index 647ab15..0000000 --- a/src/tools/imgtool/filter.cpp +++ /dev/null @@ -1,83 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/*************************************************************************** - - filter.c - - Imgtool filters - -***************************************************************************/ - -#include "filter.h" - -#include - -/* ----------------------------------------------------------------------- */ - -int64_t filter_get_info_int(filter_getinfoproc get_info, uint32_t state) -{ - union filterinfo info; - info.i = 0; - get_info(state, &info); - return info.i; -} - -void *filter_get_info_ptr(filter_getinfoproc get_info, uint32_t state) -{ - union filterinfo info; - info.p = nullptr; - get_info(state, &info); - return info.p; -} - -void *filter_get_info_fct(filter_getinfoproc get_info, uint32_t state) -{ - union 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) -{ - union filterinfo info; - info.s = nullptr; - get_info(state, &info); - return info.s; -} - -/* ----------------------------------------------------------------------- */ - -const filter_getinfoproc filters[] = -{ - filter_eoln_getinfo, - filter_cocobas_getinfo, - filter_dragonbas_getinfo, - filter_macbinary_getinfo, - filter_vzsnapshot_getinfo, - filter_vzbas_getinfo, - filter_thombas5_getinfo, - filter_thombas7_getinfo, - filter_thombas128_getinfo, - filter_thomcrypt_getinfo, - filter_bml3bas_getinfo, - filter_hp9845data_getinfo, - nullptr -}; - - - -filter_getinfoproc filter_lookup(const char *name) -{ - int i; - const char *filter_name; - - for (i = 0; filters[i]; i++) - { - filter_name = filter_get_info_string(filters[i], FILTINFO_STR_NAME); - if (!strcmp(name, filter_name)) - return filters[i]; - } - - return nullptr; -} diff --git a/src/tools/imgtool/filter.h b/src/tools/imgtool/filter.h deleted file mode 100644 index 75c1319..0000000 --- a/src/tools/imgtool/filter.h +++ /dev/null @@ -1,63 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/*************************************************************************** - - filter.h - - Imgtool filters - -***************************************************************************/ - -#ifndef FILTER_H -#define FILTER_H - -#include "library.h" - -struct imgtool_filter; - -enum -{ - /* --- the following bits of info are returned as 64-bit signed integers --- */ - FILTINFO_INT_FIRST = 0x00000, - FILTINFO_INT_STATESIZE, - - /* --- the following bits of info are returned as pointers to data or functions --- */ - FILTINFO_PTR_FIRST = 0x10000, - FILTINFO_PTR_READFILE, - FILTINFO_PTR_WRITEFILE, - FILTINFO_PTR_CHECKSTREAM, - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - FILTINFO_STR_FIRST = 0x20000, - FILTINFO_STR_NAME, - FILTINFO_STR_HUMANNAME, - FILTINFO_STR_EXTENSION -}; - -extern const filter_getinfoproc filters[]; - -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); - -/* ----------------------------------------------------------------------- */ - -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 */ diff --git a/src/tools/imgtool/formats/coco_dsk.cpp b/src/tools/imgtool/formats/coco_dsk.cpp deleted file mode 100644 index 33363b2..0000000 --- a/src/tools/imgtool/formats/coco_dsk.cpp +++ /dev/null @@ -1,1187 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/********************************************************************* - - formats/coco_dsk.c - - Tandy Color Computer / Dragon disk images - -*********************************************************************/ - -#include -#include -#include - -#include "formats/coco_dsk.h" -#include "formats/basicdsk.h" -#include "formats/imageutl.h" -#include "opresolv.h" -#include - -/* ----------------------------------------------------------------------- - * JVC (Jeff Vavasour CoCo) format - * - * Used by Jeff Vavasour's CoCo Emulators - * - * Documentation taken from Tim Linder's web site: - * http://home.netcom.com/~tlindner/JVC.html - * - * A. Header length - * The header length is determined by the file length modulo 256: - * headerSize = fileLength % 256; - * This means that the header is variable length and the minimum size - * is zero bytes, and the maximum size of 255 bytes. - * - * B. Header - * Here is a description of the header bytes: - * Byte Offset Description Default - * ----------- ----------------- ------- - * 0 Sectors per track 18 - * 1 Side count 1 - * 2 Sector size code 1 - * 3 First sector ID 1 - * 4 Sector attribute flag 0 - * - * If the sector attribute flag is zero then the track count is determined - * by the formula: - * - * (fileLength - headerSize) / (sectorsPerTrack * (128 << - * sectorSizeCode)) / sideCount - * - * If the sector attribute flag is non zero then the track count is - * determined by the more complex formula: - * - * (fileLength - headerSize) / (sectorsPerTrack * ((128 << - * sectorSizeCode) + 1) ) / sideCount - * - * If the length of the header is to short to contain the geometry desired, - * then the default values are assumed. If the header length is zero the all - * of the geometry is assumed. When creating disk images it is desirable to - * make the header length as short as possible. The header should only be - * used to deviate from the default values. - * - * The sector data begins immediately after the header. If the header length - * is zero then the sector data is at the beginning file. - * - * C. Sectors per track - * This is the number of sectors per track (ones based). A value of 18 - * means there are 18 sectors per track - * - * D. Side Count - * This is the number of sides in the disk image. Values of 1 or 2 are - * acceptable. If there are two sides then the tracks are interleaved. - * The first track in the image file is track zero side 1, the second - * track in the image file is track zero side 2. - * - * E. Sector size - * The is the same value that is stored in the wd179x ID field to - * determine sector size: - * - * 0x00 128 bytes - * 0x01 256 bytes - * 0x02 512 bytes - * 0x03 1024 bytes - * - * Other values are undefined. Every sector in the disk image must be the - * same size. - * - * F. First sector ID - * This determines the first sector ID for each track. Each successive - * sector adds one to the previous ID. If the first sector ID is 1, then - * the second sector has an ID of 2, and the third has an ID of 3. - * - * G. Sector Attribute Flag - * If this byte is non zero, then each sector contains an additional - * byte prepended to the sector data. If the attribute flag is zero then - * there are no extra bytes in front of the sector data. - * - * H. Sector attribute byte - * This byte is put at the beginning of every sector if the header flag - * is turned on. The information this byte contains is the same as the - * status register (of the wd179x) would contain when a 'Read Sector' - * command was issued. The bit fields are defined as: - * - * Bit position: - * --------------- - * 7 6 5 4 3 2 1 0 - * | | | | | | | | - * | | | | | | | +--- Not used. Set to zero. - * | | | | | | +----- Not used. Set to zero. - * | | | | | +------- Not used. Set to zero. - * | | | | +--------- Set on CRC error. - * | | | +----------- Set if sector not found. - * | | +------------- Record type: 1 - Deleted Data Mark, 0 - Data Mark. - * | +--------------- Not Used. Set to zero. - * +----------------- Not Used. Set to zero. - * - * ----------------------------------------------------------------------- */ - -static int coco_jvc_decode_header(floppy_image_legacy *floppy, uint64_t size, - struct basicdsk_geometry *geometry) -{ - uint8_t header[256]; - uint8_t sector_attribute_flag; - uint16_t physical_bytes_per_sector; - uint32_t header_size, file_size; - struct basicdsk_geometry dummy_geometry; - - if (geometry) - memset(geometry, 0, sizeof(*geometry)); - else - geometry = &dummy_geometry; - - if (size > 0xFFFFFFFF) - return -1; - file_size = (uint32_t) size; - - /* read the header */ - header_size = (uint32_t) file_size % 0x100; - floppy_image_read(floppy, header, 0, header_size); - geometry->offset = header_size; - - /* byte offset 0 - sectors per track */ - geometry->sectors = (header_size > 0) ? header[0] : 18; - if (geometry->sectors <= 0) - return -1; - - /* byte offset 1 - side count */ - geometry->heads = (header_size > 1) ? header[1] : 1; - if (geometry->heads <= 0) - return -1; - - /* byte offset 2 - sector size code */ - geometry->sector_length = 128 << ((header_size > 2) ? header[2] : 1); - if (geometry->sector_length <= 0) - return -1; - - /* byte offset 3 - first sector ID */ - geometry->first_sector_id = (header_size > 3) ? header[3] : 1; - - /* byte offset 4 - sector attribute flag */ - sector_attribute_flag = (header_size > 4) ? header[4] : 0; - if (sector_attribute_flag != 0) - return -1; /* we do not support sector attribute flags */ - - physical_bytes_per_sector = geometry->sector_length; - if (sector_attribute_flag) - physical_bytes_per_sector++; - - geometry->tracks = (file_size - header_size) / geometry->sectors / geometry->heads / physical_bytes_per_sector; - - /* do we have an oddball size? reject this file if not */ - if ((file_size - header_size) % physical_bytes_per_sector) - return -1; - - /* minimum of 35 tracks; support degenerate JVC files */ - if (geometry->tracks < 35) - geometry->tracks = 35; - - return 0; -} - - - -static FLOPPY_IDENTIFY(coco_jvc_identify) -{ - uint64_t size; - size = floppy_image_size(floppy); - *vote = coco_jvc_decode_header(floppy, size, NULL) ? 0 : 100; - return FLOPPY_ERROR_SUCCESS; -} - - - -static FLOPPY_CONSTRUCT(coco_jvc_construct) -{ - struct basicdsk_geometry geometry; - uint8_t header[5]; - size_t header_size; - - 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 = params->lookup_int(PARAM_FIRST_SECTOR_ID); - geometry.sector_length = params->lookup_int(PARAM_SECTOR_LENGTH); - - header[0] = (uint8_t) geometry.sectors; - header[1] = (uint8_t) geometry.heads; - header[2] = (uint8_t) compute_log2(geometry.sector_length) - 7; - header[3] = (uint8_t) geometry.first_sector_id; - header[4] = 0; - - /* now that we have the header computed, figure out the header size */ - header_size = 0; - if (header[0] != 18) - header_size = 1; - if (header[1] != 1) - header_size = 2; - if (header[2] != 1) - header_size = 3; - if (header[3] != 1) - header_size = 4; - if (header[4] != 0) - header_size = 5; - - geometry.offset = header_size; - - floppy_image_write(floppy, header, 0, header_size); - } - else - { - /* load */ - if (coco_jvc_decode_header(floppy, floppy_image_size(floppy), &geometry)) - return FLOPPY_ERROR_INVALIDIMAGE; - } - return basicdsk_construct(floppy, &geometry); -} - - -/* ----------------------------------------------------------------------- - * OS-9 file format - * - * This file format is largely a hack because there are a large amount of - * disk images that do not have geometry image separate from the disk image - * itself. So we support OS-9 images with are simply basic disks whose - * geometry is determined by the disk image. - * - * OS-9 images identified by an LSN; which are simply blocks of 256 bytes - * - * LSN0 - * Byte size use - * $00 3 sectors on disk - * $03 1 track size in sectors - * $04 2 bytes in allocation bit map; typically 1bit/sector so for - * 35 tracks of 18 sectors each that's $4E (single sided disk) - * 40 tracks per side, 18 sectors each = $B4 - * $06 2 sectors per bit in allocation map; normally 1 - * $08 3 LSN of root directory; normally 2 but depends on size of - * $04 value - * $0B 2 owner's user number; normally 0 - * $0D 1 disk attributes; normally $FF - * $0E 2 pseudo random number for identification - * $10 1 disk format; typical is 3 - * %00000001 0=single side 1=double side - * %00000010 0=single density (non Coco) 1=double density - * %00000100 0=48tracks/inch 1=96tracks/inch - * $11 2 sectors per track; normal is $12 skip several not needed - * for Format - * $1A 5 date of creation Y:M:D:H:M - * $1F 32 ASCII name of disk, last letter has $80 added to it, - * the full 32 bytes do not need to be used. - * - * Allocation bit map, fill with zeros and set bits from low to high as - * sectors are used. So, for a fresh disk sectors LSN0,LSN1,LSN2, and LSN3 - * will be in use so the first byte will be $FF $C0 and all others - * in the map are $00 - * - * Root directory LSN2 - * Byte size use - * $00 1 attributes will be $BF - * $01 2 owners ID will be $0000 - * $03 5 date last modified will be creation date Y:M:D:H:M - * $08 1 link count; set to $02 - * $09 4 file size in bytes, set to $40 - * $0D 3 date created Y:M:D - * $10 3 block LSN set to current sector number+1 ie $03 in this case - * $13 2 size in sectors of directory block, set to $07 - * All other bytes in sector set to $00 - * LSN3 first sector of directory with names - * Fill sector with all $00 and then set listed bytes - * $00 2 value $2EAE which is .. with last byte+$80 - * $1F 1 value $02 LSN for start of this directory as there is - * none higher in tree - * $20 1 value $AE which is . with $80 added - * $3F 1 value $02 LSN for start of this directory - * ----------------------------------------------------------------------- */ - -static floperr_t coco_os9_readheader(floppy_image_legacy *floppy, struct basicdsk_geometry *geometry) -{ - uint8_t header[0x20]; - int total_sectors; - - floppy_image_read(floppy, header, 0, sizeof(header)); - - total_sectors = (header[0x00] << 16) | (header[0x01] << 8) | header[0x02]; - - memset(geometry, 0, sizeof(*geometry)); - geometry->first_sector_id = 1; - geometry->sector_length = 256; - geometry->sectors = (header[0x11] << 8) + header[0x12]; - geometry->heads = (header[0x10] & 0x01) ? 2 : 1; - - if (!geometry->sectors) - return FLOPPY_ERROR_INVALIDIMAGE; - - geometry->tracks = total_sectors / geometry->sectors / geometry->heads; - - if (total_sectors != geometry->tracks * geometry->sectors * geometry->heads) - return FLOPPY_ERROR_INVALIDIMAGE; - - return FLOPPY_ERROR_SUCCESS; -} - - - -static floperr_t coco_os9_post_format(floppy_image_legacy *floppy, util::option_resolution *params) -{ - uint8_t header[0x0400]; - floperr_t err; - time_t t; - struct tm *ltime; - int heads, tracks, sectors, total_sectors; - - heads = params->lookup_int(PARAM_HEADS); - tracks = params->lookup_int(PARAM_TRACKS); - sectors = params->lookup_int(PARAM_SECTORS); - total_sectors = heads * tracks * sectors; - - /* write the initial header */ - time(&t); - ltime = localtime(&t); - - memset(&header, 0, sizeof(header)); - header[0x0000] = (uint8_t) (total_sectors >> 16); - header[0x0001] = (uint8_t) (total_sectors >> 8); - header[0x0002] = (uint8_t) (total_sectors >> 0); - header[0x0003] = (uint8_t) sectors; - header[0x0004] = (uint8_t) (((total_sectors + 7) / 8) >> 8); - header[0x0005] = (uint8_t) (((total_sectors + 7) / 8) >> 0); - header[0x0006] = 0x00; - header[0x0007] = 0x01; - header[0x0008] = 0x00; - header[0x0009] = 0x00; - header[0x000a] = 0x02; - header[0x000b] = 0x00; - header[0x000c] = 0x00; - header[0x000d] = 0xff; - header[0x000e] = floppy_random_byte(floppy); - header[0x000f] = floppy_random_byte(floppy); - header[0x0010] = (heads == 2) ? 3 : 2; - header[0x0011] = (uint8_t) (sectors >> 8); - header[0x0012] = (uint8_t) (sectors >> 0); - header[0x001A] = (uint8_t) ltime->tm_year; - header[0x001B] = (uint8_t) ltime->tm_mon + 1; - header[0x001C] = (uint8_t) ltime->tm_mday; - header[0x001D] = (uint8_t) ltime->tm_hour; - header[0x001E] = (uint8_t) ltime->tm_min; - header[0x001F] = 0xA0; - header[0x0100] = 0xFF; - header[0x0101] = 0xC0; - header[0x0200] = 0xBF; - header[0x0201] = 0x00; - header[0x0202] = 0x00; - header[0x0203] = (uint8_t) ltime->tm_year; - header[0x0204] = (uint8_t) ltime->tm_mon + 1; - header[0x0205] = (uint8_t) ltime->tm_mday; - header[0x0206] = (uint8_t) ltime->tm_hour; - header[0x0207] = (uint8_t) ltime->tm_min; - header[0x0208] = 0x02; - header[0x0209] = 0x00; - header[0x020A] = 0x00; - header[0x020B] = 0x00; - header[0x020C] = 0x40; - header[0x020D] = (uint8_t) (ltime->tm_year % 100); - header[0x020E] = (uint8_t) ltime->tm_mon; - header[0x020F] = (uint8_t) ltime->tm_mday; - header[0x0210] = 0x00; - header[0x0211] = 0x00; - header[0x0212] = 0x03; - header[0x0213] = 0x00; - header[0x0214] = 0x07; - header[0x0300] = 0x2E; - header[0x0301] = 0xAE; - header[0x031F] = 0x02; - header[0x0320] = 0xAE; - header[0x033F] = 0x02; - - if (total_sectors % 8) - header[0x0100 + (total_sectors / 8)] = 0xFF >> (total_sectors % 8); - - err = floppy_write_sector(floppy, 0, 0, 1, 0, &header[0x0000], 256, 0); - if (err) - return err; - - err = floppy_write_sector(floppy, 0, 0, 2, 0, &header[0x0100], 256, 0); - if (err) - return err; - - err = floppy_write_sector(floppy, 0, 0, 3, 0, &header[0x0200], 256, 0); - if (err) - return err; - - err = floppy_write_sector(floppy, 0, 0, 4, 0, &header[0x0300], 256, 0); - if (err) - return err; - - return FLOPPY_ERROR_SUCCESS; -} - - - -static FLOPPY_IDENTIFY(coco_os9_identify) -{ - struct basicdsk_geometry geometry; - *vote = coco_os9_readheader(floppy, &geometry) ? 0 : 100; - return FLOPPY_ERROR_SUCCESS; -} - - - -static FLOPPY_CONSTRUCT(coco_os9_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 = params->lookup_int(PARAM_FIRST_SECTOR_ID); - geometry.sector_length = params->lookup_int(PARAM_SECTOR_LENGTH); - } - else - { - /* open */ - err = coco_os9_readheader(floppy, &geometry); - if (err) - return err; - } - - /* actually construct the image */ - err = basicdsk_construct(floppy, &geometry); - floppy_callbacks(floppy)->post_format = coco_os9_post_format; - return err; -} - - - -/* ----------------------------------------------------------------------- - * VDK file format - * - * Used by Paul Burgin's PC-Dragon emulator - * - * Offset Bytes Field Description - * ------ ----- ------------ ----------- - * 0 1 magic1 Signature byte 1 ('d') - * 1 1 magic2 Signature byte 2 ('k') - * 2 2 header_len Total header length (little endian) - * 4 1 ver_actual Version of the VDK format (0x10) - * 5 1 ver_compat Backwards compatibility version (0x10) - * 6 1 source_id Identify of the file source - * 7 1 source_ver Version of the file source - * 8 1 tracks Number of tracks - * 9 1 sides Number of sides (1-2) - * 10 1 flags Various flags - * bit 0: Write protect - * bit 1: A Lock - * bit 2: F Lock - * bit 3: Disk set - * 11 1 compression Compression flags (bits 0-2) and name length - * ----------------------------------------------------------------------- */ - - - -static int coco_vdk_decode_header(floppy_image_legacy *floppy, struct basicdsk_geometry *geometry) -{ - uint8_t header[12]; - uint8_t heads, tracks, sectors; - uint16_t sector_length, offset; - uint64_t size; - - size = floppy_image_size(floppy); - - floppy_image_read(floppy, header, 0, sizeof(header)); - - if (header[0] != 'd') - return -1; - if (header[1] != 'k') - return -1; - if (header[5] != 0x10) - return -1; - if (header[11] & 0x07) - return -1; - - heads = header[9]; - tracks = header[8]; - sectors = 18; - sector_length = 0x100; - - offset = header[3] * 0x100 + header[2]; - - if (size != ((uint32_t) heads * tracks * sectors * sector_length + offset)) - return -1; - - if (geometry) - { - memset(geometry, 0, sizeof(*geometry)); - geometry->heads = heads; - geometry->tracks = tracks; - geometry->sectors = sectors; - geometry->first_sector_id = 1; - geometry->sector_length = sector_length; - geometry->offset = offset; - } - return 0; -} - - - -static FLOPPY_IDENTIFY(coco_vdk_identify) -{ - *vote = coco_vdk_decode_header(floppy, NULL) ? 0 : 100; - return FLOPPY_ERROR_SUCCESS; -} - - - -static FLOPPY_CONSTRUCT(coco_vdk_construct) -{ - struct basicdsk_geometry geometry; - uint8_t header[12]; - - if (params) - { - /* create */ - memset(&geometry, 0, sizeof(geometry)); - geometry.heads = params->lookup_int(PARAM_HEADS); - geometry.tracks = params->lookup_int(PARAM_TRACKS); - geometry.sectors = 18; - geometry.first_sector_id = 1; - geometry.sector_length = 256; - geometry.offset = sizeof(header); - - memset(&header, 0, sizeof(header)); - header[0] = 'd'; - header[1] = 'k'; - header[2] = (uint8_t) (sizeof(header) >> 0); - header[3] = (uint8_t) (sizeof(header) >> 8); - header[4] = 0x10; - header[5] = 0x10; - header[8] = (uint8_t) geometry.tracks; - header[9] = (uint8_t) geometry.heads; - - floppy_image_write(floppy, header, 0, sizeof(header)); - } - else - { - /* load */ - if (coco_vdk_decode_header(floppy, &geometry)) - return FLOPPY_ERROR_INVALIDIMAGE; - } - return basicdsk_construct(floppy, &geometry); -} - - - -/* ----------------------------------------------------------------------- - * DMK file format - * - * David M. Keil's disk image format is aptly called an 'on disk' image - * format. This means that whatever written to the disk is enocded into - * the image file. IDAMS, sector headers, traling CRCs, and intra sector - * spacing. * - * - * HEADER DESCRIPTION: - * - * Offset Bytes Field Description - * ------ ----- ------------ ----------- - * 0 1 write_prot 0xff = Writed Protected, 0x00 = R/W - * 1 1 tracks Number of tracks - * 2 2 track_length Bytes per track (little endian) - * 4 1 disk_options Miscellaneous flags - * bit 0-3: Unused - * bit 4: 1=single sided 0=dbl - * bit 5: Unused - * bit 6: Single density? - * bit 6: Ignore density flags? - * 5 7 reserved Reserved for future use - * 12 4 real_disk_code If this is 0x12345678 (little endian) - * then access a real disk drive - * (unsupported) - * - * Each track begins with a track TOC, consisting of 64 little endian 16-bit - * integers. Each integer has the following format: - * bit 0-13: Offset from beginning of track to 'FE' byte of IDAM - * Note these are always sorted from first to last. All empty - * entries are 0x00 - * bit 14: Undefined (reserved) - * bit 15: Sector double density (0=SD 1=DD) - * ----------------------------------------------------------------------- */ - -struct dmk_tag -{ - int heads; - int tracks; - uint32_t track_size; -}; - -#define DMK_HEADER_LEN 16 -#define DMK_TOC_LEN 64 -#define DMK_IDAM_LENGTH 7 -#define DMK_DATA_GAP 80 -#define DMK_LEAD_IN 32 -#define DMK_EXTRA_TRACK_LENGTH 156 - -#define dmk_idam_type(x) (x)[0] -#define dmk_idam_track(x) (x)[1] -#define dmk_idam_side(x) (x)[2] -#define dmk_idam_sector(x) (x)[3] -#define dmk_idam_sectorlength(x) (x)[4] -#define dmk_idam_crc(x) (((x)[5] << 8) + (x)[6]) -#define dmk_idam_set_crc(x, crc) (x)[5] = ((crc) >> 8); (x)[6] = ((crc) >> 0); - - -static struct dmk_tag *get_dmk_tag(floppy_image_legacy *floppy) -{ - return (dmk_tag *)floppy_tag(floppy); -} - - -static floperr_t coco_dmk_get_offset(floppy_image_legacy *floppy, int head, int track, uint64_t *offset) -{ - struct dmk_tag *tag = get_dmk_tag(floppy); - - if ((head < 0) || (head >= tag->heads) || (track < 0) || (track >= tag->tracks)) - return FLOPPY_ERROR_SEEKERROR; - - *offset = track; - *offset *= tag->heads; - *offset += head; - *offset *= tag->track_size; - *offset += DMK_HEADER_LEN; - return FLOPPY_ERROR_SUCCESS; -} - - - -static uint32_t coco_dmk_min_track_size(int sectors, int sector_length) -{ - int sector_physical_length; - sector_physical_length = 8 + 3 + DMK_IDAM_LENGTH + 22 + 12 + 3 + 1 + sector_length + 2 + 24; - return DMK_TOC_LEN * 2 + DMK_LEAD_IN + (sectors * sector_physical_length); -} - - - -static floperr_t coco_dmk_read_track(floppy_image_legacy *floppy, int head, int track, uint64_t offset, void *buffer, size_t buflen) -{ - floperr_t err; - uint64_t track_offset; - - err = coco_dmk_get_offset(floppy, head, track, &track_offset); - if (err) - return err; - - floppy_image_read(floppy, buffer, offset + track_offset, buflen); - return FLOPPY_ERROR_SUCCESS; -} - - - -static floperr_t coco_dmk_write_track(floppy_image_legacy *floppy, int head, int track, uint64_t offset, const void *buffer, size_t buflen) -{ - floperr_t err; - uint64_t track_offset; - - err = coco_dmk_get_offset(floppy, head, track, &track_offset); - if (err) - return err; - - floppy_image_write(floppy, buffer, offset + track_offset, buflen); - return FLOPPY_ERROR_SUCCESS; -} - - - -static floperr_t coco_dmk_get_track_data_offset(floppy_image_legacy *floppy, int head, int track, uint64_t *offset) -{ - *offset = DMK_TOC_LEN + 1; - return FLOPPY_ERROR_SUCCESS; -} - - - -static floperr_t coco_dmk_format_track(floppy_image_legacy *floppy, int head, int track, util::option_resolution *params) -{ - int sectors; - int sector_length; - int interleave; - int first_sector_id; - floperr_t err; - int physical_sector; - int logical_sector; - int track_position; - uint16_t idam_offset; - uint16_t crc; - uint8_t *track_data; - void *track_data_v; - uint32_t max_track_size; - - sectors = params->lookup_int(PARAM_SECTORS); - sector_length = params->lookup_int(PARAM_SECTOR_LENGTH); - interleave = params->lookup_int(PARAM_INTERLEAVE); - first_sector_id = params->lookup_int(PARAM_FIRST_SECTOR_ID); - - max_track_size = get_dmk_tag(floppy)->track_size; - - if (sectors > DMK_TOC_LEN) - return FLOPPY_ERROR_INTERNAL; - - if (max_track_size < coco_dmk_min_track_size(sectors, sector_length)) - return FLOPPY_ERROR_NOSPACE; - - err = floppy_load_track(floppy, head, track, true, &track_data_v, NULL); - if (err) - return err; - track_data = (uint8_t *) track_data_v; - - // set up sector map - std::vector sector_map(sectors, -1); - - physical_sector = 0; - for (logical_sector = 0; logical_sector < sectors; logical_sector++) - { - while(sector_map[physical_sector] >= 0) - { - physical_sector++; - physical_sector %= sectors; - } - - sector_map[physical_sector] = logical_sector + first_sector_id; - physical_sector += interleave + 1; - physical_sector %= sectors; - } - - // set up track table of contents - physical_sector = 0; - track_position = DMK_TOC_LEN * 2 + DMK_LEAD_IN; - while(physical_sector < DMK_TOC_LEN) - { - if (physical_sector >= sectors) - { - // no more sectors - idam_offset = 0; - } - else - { - // this is a sector - logical_sector = sector_map[physical_sector]; - - // write the sector - memset(&track_data[track_position], 0x00, 8); - track_position += 8; - - memset(&track_data[track_position], 0xA1, 3); - track_position += 3; - - idam_offset = track_position | 0x8000; - dmk_idam_type( &track_data[track_position]) = 0xFE; - dmk_idam_track( &track_data[track_position]) = track; - dmk_idam_side( &track_data[track_position]) = head; - dmk_idam_sector( &track_data[track_position]) = logical_sector; - dmk_idam_sectorlength( &track_data[track_position]) = compute_log2(sector_length / 128); - crc = ccitt_crc16(0xcdb4, &track_data[track_position], DMK_IDAM_LENGTH - 2); - dmk_idam_set_crc( &track_data[track_position], crc); - track_position += DMK_IDAM_LENGTH; - - memset(&track_data[track_position], 0x4E, 22); - track_position += 22; - - memset(&track_data[track_position], 0x00, 12); - track_position += 12; - - memset(&track_data[track_position], 0xA1, 3); - track_position += 3; - - // write sector body - track_data[track_position] = 0xFB; - memset(&track_data[track_position + 1], floppy_get_filler(floppy), sector_length); - crc = ccitt_crc16(0xcdb4, &track_data[track_position], sector_length + 1); - track_data[track_position + sector_length + 1] = (uint8_t) (crc >> 8); - track_data[track_position + sector_length + 2] = (uint8_t) (crc >> 0); - track_position += sector_length + 3; - - // write sector footer - memset(&track_data[track_position], 0x4E, 24); - track_position += 24; - } - - // write the TOC entry - track_data[physical_sector * 2 + 0] = (uint8_t) (idam_offset >> 0); - track_data[physical_sector * 2 + 1] = (uint8_t) (idam_offset >> 8); - - physical_sector++; - } - - // write track lead in - memset(&track_data[physical_sector * 2], 0x4e, DMK_LEAD_IN); - - // write track footer - assert(max_track_size >= (uint32_t)track_position); - memset(&track_data[track_position], 0x4e, max_track_size - track_position); - - return FLOPPY_ERROR_SUCCESS; -} - - - -static int coco_dmk_get_heads_per_disk(floppy_image_legacy *floppy) -{ - return get_dmk_tag(floppy)->heads; -} - - - -static int coco_dmk_get_tracks_per_disk(floppy_image_legacy *floppy) -{ - return get_dmk_tag(floppy)->tracks; -} - - - -static uint32_t coco_dmk_get_track_size(floppy_image_legacy *floppy, int head, int track) -{ - return get_dmk_tag(floppy)->track_size; -} - - - -static floperr_t coco_dmk_seek_sector_in_track(floppy_image_legacy *floppy, int head, int track, int sector, int sector_is_index, int dirtify, uint8_t **sector_data, uint32_t *sector_length) -{ - struct dmk_tag *tag = get_dmk_tag(floppy); - floperr_t err; - uint32_t idam_offset = 0; - uint16_t calculated_crc; - size_t i; - size_t offs; - int state; - uint8_t *track_data; - void *track_data_v; - size_t track_length; - size_t sec_len; - - err = floppy_load_track(floppy, head, track, dirtify, &track_data_v, &track_length); - if (err) - return err; - track_data = (uint8_t *) track_data_v; - - /* search for matching IDAM */ - for (i = 0; i < DMK_TOC_LEN; i++) - { - idam_offset = track_data[i * 2 + 1]; - idam_offset <<= 8; - idam_offset |= track_data[i * 2 + 0]; - idam_offset &= 0x3FFF; - - if (idam_offset == 0) - { - /* we've reached the end of the road */ - i = DMK_TOC_LEN; - break; - } - - if ((idam_offset + DMK_IDAM_LENGTH) >= tag->track_size) - continue; - - calculated_crc = ccitt_crc16(0xCDB4, &track_data[idam_offset], DMK_IDAM_LENGTH - 2); - - if (calculated_crc == dmk_idam_crc(&track_data[idam_offset])) - { - if (sector_is_index) - { - /* the sector is indexed; decrement the index and go */ - if (sector-- == 0) - break; - } - else - { - /* check IDAM integrity and check for matching sector */ - if (sector == dmk_idam_sector(&track_data[idam_offset]) -/* && (track == dmk_idam_track(&track_data[idam_offset])) */ -/* && (head == dmk_idam_side(&track_data[idam_offset])) */ - ) - break; - } - } - } - - if (i >= DMK_TOC_LEN) - return FLOPPY_ERROR_SEEKERROR; - - /* we found a matching sector ID */ - state = 0; - offs = idam_offset + DMK_IDAM_LENGTH; - - /* find pattern 0xA1A1FB; this represents the start of a data sector */ - for (i = 0; i < DMK_DATA_GAP; i++) - { - /* overflowing the track? */ - if ((i + offs) >= tag->track_size) - return FLOPPY_ERROR_SEEKERROR; - - if (track_data[offs + i] == 0xA1) - state++; - else if ((track_data[offs + i] == 0xFB) && state) - break; - else - state = 0; - } - if (i >= DMK_DATA_GAP) - return FLOPPY_ERROR_SEEKERROR; - - offs += i + 1; - sec_len = 128 << dmk_idam_sectorlength(&track_data[idam_offset]); - - if ((offs + sec_len) > track_length) - return FLOPPY_ERROR_INVALIDIMAGE; - - if (sector_data) - *sector_data = track_data + offs; - if (sector_length) - *sector_length = sec_len; - return FLOPPY_ERROR_SUCCESS; -} - - - -static floperr_t coco_dmk_get_sector_length(floppy_image_legacy *floppy, int head, int track, int sector, uint32_t *sector_length) -{ - return coco_dmk_seek_sector_in_track(floppy, head, track, sector, false, false, NULL, sector_length); -} - - - -static floperr_t coco_dmk_get_indexed_sector_info(floppy_image_legacy *floppy, int head, int track, int sector_index, int *cylinder, int *side, int *sector, uint32_t *sector_length, unsigned long *flags) -{ - floperr_t err; - uint32_t idam_offset; - const uint8_t *track_data; - void *track_data_v; - - if (sector_index*2 >= DMK_TOC_LEN) - return FLOPPY_ERROR_SEEKERROR; - - err = floppy_load_track(floppy, head, track, false, &track_data_v, NULL); - if (err) - return err; - track_data = (uint8_t *) track_data_v; - - idam_offset = track_data[sector_index * 2 + 1]; - idam_offset <<= 8; - idam_offset |= track_data[sector_index * 2 + 0]; - idam_offset &= 0x3FFF; - - if (idam_offset == 0) - return FLOPPY_ERROR_SEEKERROR; - - if (cylinder) - *cylinder = dmk_idam_track(&track_data[idam_offset]); - if (side) - *side = dmk_idam_side(&track_data[idam_offset]); - if (sector) - *sector = dmk_idam_sector(&track_data[idam_offset]); - if (sector_length) - *sector_length = 128 << dmk_idam_sectorlength(&track_data[idam_offset]); - if (flags) - /* TODO: read DAM or DDAM and determine flags */ - *flags = 0; - return FLOPPY_ERROR_SUCCESS; -} - - - -static floperr_t internal_coco_dmk_read_sector(floppy_image_legacy *floppy, int head, int track, int sector, int sector_is_index, void *buffer, size_t buflen) -{ - floperr_t err; - uint32_t sector_length; - uint16_t crc_on_disk; - uint16_t calculated_crc; - uint8_t *sector_data; - - err = coco_dmk_seek_sector_in_track(floppy, head, track, sector, sector_is_index, false, §or_data, §or_length); - if (err) - return err; - - crc_on_disk = sector_data[sector_length + 0]; - crc_on_disk <<= 8; - crc_on_disk += sector_data[sector_length + 1]; - - calculated_crc = ccitt_crc16(0xE295, sector_data, sector_length); - if (calculated_crc != crc_on_disk) - return FLOPPY_ERROR_INVALIDIMAGE; - - memcpy(buffer, sector_data, std::min(size_t(sector_length), buflen)); - - return FLOPPY_ERROR_SUCCESS; -} - - - -static floperr_t internal_coco_dmk_write_sector(floppy_image_legacy *floppy, int head, int track, int sector, int sector_is_index, const void *buffer, size_t buflen, int ddam) -{ - floperr_t err; - uint32_t sector_length; - uint8_t *sector_data; - uint16_t crc; - - err = coco_dmk_seek_sector_in_track(floppy, head, track, sector, sector_is_index, true, §or_data, §or_length); - if (err) - return err; - - if (buflen > sector_length) - return FLOPPY_ERROR_INTERNAL; - - memcpy(sector_data, buffer, buflen); - - crc = ccitt_crc16(0xE295, sector_data, sector_length); - sector_data[sector_length + 0] = crc >> 8; - sector_data[sector_length + 1] = crc >> 0; - return FLOPPY_ERROR_SUCCESS; -} - - - -static floperr_t coco_dmk_read_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen) -{ - return internal_coco_dmk_read_sector(floppy, head, track, sector, false, buffer, buflen); -} - -static floperr_t coco_dmk_write_sector(floppy_image_legacy *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam) -{ - return internal_coco_dmk_write_sector(floppy, head, track, sector, false, buffer, buflen, ddam); -} - -static floperr_t coco_dmk_read_indexed_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen) -{ - return internal_coco_dmk_read_sector(floppy, head, track, sector, true, buffer, buflen); -} - -static floperr_t coco_dmk_write_indexed_sector(floppy_image_legacy *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam) -{ - return internal_coco_dmk_write_sector(floppy, head, track, sector, true, buffer, buflen, ddam); -} - - - -static void coco_dmk_interpret_header(floppy_image_legacy *floppy, int *heads, int *tracks, int *track_size) -{ - uint8_t header[DMK_HEADER_LEN]; - - floppy_image_read(floppy, header, 0, DMK_HEADER_LEN); - - if (tracks) - *tracks = header[1]; - if (heads) - *heads = (header[4] & 0x10) ? 1 : 2; - if (track_size) - *track_size = ((int) header[3]) * 0x100 + header[2]; -} - - - -FLOPPY_CONSTRUCT(coco_dmk_construct) -{ - struct FloppyCallbacks *callbacks; - struct dmk_tag *tag; - uint8_t header[DMK_HEADER_LEN]; - int heads, tracks, track_size, sectors, sector_length; - - if (params) - { - heads = params->lookup_int(PARAM_HEADS); - tracks = params->lookup_int(PARAM_TRACKS); - sectors = params->lookup_int(PARAM_SECTORS); - sector_length = params->lookup_int(PARAM_SECTOR_LENGTH); - - track_size = coco_dmk_min_track_size(sectors, sector_length) + DMK_EXTRA_TRACK_LENGTH; - - memset(header, 0, sizeof(header)); - header[1] = tracks; - header[2] = track_size >> 0; - header[3] = track_size >> 8; - header[4] = (heads == 2) ? 0x00 : 0x10; - - floppy_image_write(floppy, header, 0, sizeof(header)); - } - else - { - coco_dmk_interpret_header(floppy, &heads, &tracks, &track_size); - } - - tag = (dmk_tag *)floppy_create_tag(floppy, sizeof(struct dmk_tag)); - if (!tag) - return FLOPPY_ERROR_OUTOFMEMORY; - tag->heads = heads; - tag->track_size = track_size; - tag->tracks = tracks; - - callbacks = floppy_callbacks(floppy); - callbacks->read_track = coco_dmk_read_track; - callbacks->write_track = coco_dmk_write_track; - callbacks->get_track_data_offset = coco_dmk_get_track_data_offset; - callbacks->format_track = coco_dmk_format_track; - callbacks->get_heads_per_disk = coco_dmk_get_heads_per_disk; - callbacks->get_tracks_per_disk = coco_dmk_get_tracks_per_disk; - callbacks->get_track_size = coco_dmk_get_track_size; - callbacks->get_sector_length = coco_dmk_get_sector_length; - callbacks->get_indexed_sector_info = coco_dmk_get_indexed_sector_info; - callbacks->read_sector = coco_dmk_read_sector; - callbacks->write_sector = coco_dmk_write_sector; - callbacks->read_indexed_sector = coco_dmk_read_indexed_sector; - callbacks->write_indexed_sector = coco_dmk_write_indexed_sector; - - return FLOPPY_ERROR_SUCCESS; -} - - - -FLOPPY_IDENTIFY(coco_dmk_identify) -{ - int heads, tracks, track_size; - uint64_t size, expected_size; - - size = floppy_image_size(floppy); - coco_dmk_interpret_header(floppy, &heads, &tracks, &track_size); - expected_size = DMK_HEADER_LEN + (heads * tracks * track_size); - *vote = (size == expected_size) ? 100 : 0; - return FLOPPY_ERROR_SUCCESS; -} - - - -/* ----------------------------------------------------------------------- */ - -LEGACY_FLOPPY_OPTIONS_START( coco ) - LEGACY_FLOPPY_OPTION( coco_jvc, "dsk", "CoCo JVC disk image", coco_jvc_identify, coco_jvc_construct, NULL, - HEADS([1]-2) - TRACKS([35]-255) - SECTORS(1-[18]-255) - SECTOR_LENGTH(128/[256]/512/1024) - FIRST_SECTOR_ID(0-[1])) - LEGACY_FLOPPY_OPTION( coco_os9, "os9", "CoCo OS-9 disk image", coco_os9_identify, coco_os9_construct, NULL, - HEADS([1]-2) - TRACKS([35]-255) - SECTORS(1-[18]-255) - SECTOR_LENGTH([256]) - FIRST_SECTOR_ID([1])) - LEGACY_FLOPPY_OPTION( coco_vdk, "vdk", "CoCo VDK disk image", coco_vdk_identify, coco_vdk_construct, NULL, - HEADS([1]-2) - TRACKS([35]-255) - SECTORS([18]) - SECTOR_LENGTH([256]) - FIRST_SECTOR_ID([1])) - LEGACY_FLOPPY_OPTION( coco_dmk, "dsk,dmk", "CoCo DMK disk image", coco_dmk_identify, coco_dmk_construct, NULL, - HEADS([1]-2) - TRACKS([35]-255) - SECTORS(1-[18]) - SECTOR_LENGTH(128/[256]/512/1024/2048/4096/8192) - INTERLEAVE(0-[6]-17) - FIRST_SECTOR_ID(0-[1])) -LEGACY_FLOPPY_OPTIONS_END diff --git a/src/tools/imgtool/formats/coco_dsk.h b/src/tools/imgtool/formats/coco_dsk.h deleted file mode 100644 index bf9bccc..0000000 --- a/src/tools/imgtool/formats/coco_dsk.h +++ /dev/null @@ -1,24 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/********************************************************************* - - formats/coco_dsk.h - - Tandy Color Computer / Dragon disk images - -*********************************************************************/ - -#ifndef COCO_DSK_H -#define COCO_DSK_H - -#include "formats/flopimg_legacy.h" - - -/**************************************************************************/ - -LEGACY_FLOPPY_OPTIONS_EXTERN(coco); - -FLOPPY_IDENTIFY(coco_dmk_identify); -FLOPPY_CONSTRUCT(coco_dmk_construct); - -#endif /* COCO_DSK_H */ diff --git a/src/tools/imgtool/formats/pc_dsk_legacy.cpp b/src/tools/imgtool/formats/pc_dsk_legacy.cpp deleted file mode 100644 index 771f0de..0000000 --- a/src/tools/imgtool/formats/pc_dsk_legacy.cpp +++ /dev/null @@ -1,140 +0,0 @@ -// 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 deleted file mode 100644 index 14cb33f..0000000 --- a/src/tools/imgtool/formats/pc_dsk_legacy.h +++ /dev/null @@ -1,21 +0,0 @@ -// 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_legacy.cpp b/src/tools/imgtool/formats/vt_dsk_legacy.cpp deleted file mode 100644 index 6cf5785..0000000 --- a/src/tools/imgtool/formats/vt_dsk_legacy.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// license:GPL-2.0+ -// copyright-holders:Juergen Buchmueller -/********************************************************************* - - formats/vt_dsk_legacy.cpp - - VTech Laser/VZ disk images (legacy support) - -*********************************************************************/ - -#include "formats/vt_dsk_legacy.h" -#include "formats/basicdsk.h" - -#include "opresolv.h" - -#include - -static FLOPPY_IDENTIFY(vz_identify) -{ - uint64_t size = floppy_image_size(floppy); - *vote = ((size == 98560) || (size == 99200) || (size == 99184)) ? 100 : 0; - return FLOPPY_ERROR_SUCCESS; -} - -static FLOPPY_CONSTRUCT(vz_construct) -{ - struct basicdsk_geometry geometry; - memset(&geometry, 0, sizeof(geometry)); - - if (params) - { - 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 = params->lookup_int(PARAM_FIRST_SECTOR_ID); - geometry.sector_length = params->lookup_int(PARAM_SECTOR_LENGTH); - } - else - { - geometry.heads = 1; - geometry.tracks = 40; - geometry.sectors = 16; - geometry.first_sector_id = 0; - geometry.sector_length = floppy_image_size(floppy)/geometry.tracks/geometry.sectors; - } - - return basicdsk_construct(floppy, &geometry); -} - - -LEGACY_FLOPPY_OPTIONS_START(vz) - LEGACY_FLOPPY_OPTION(vtech1, "dsk", "Laser/VZ disk image", vz_identify, vz_construct, NULL, - HEADS([1]) - TRACKS([40]) - SECTORS([16]) - SECTOR_LENGTH([154]) - FIRST_SECTOR_ID([0])) -LEGACY_FLOPPY_OPTIONS_END diff --git a/src/tools/imgtool/formats/vt_dsk_legacy.h b/src/tools/imgtool/formats/vt_dsk_legacy.h deleted file mode 100644 index fe8f0dd..0000000 --- a/src/tools/imgtool/formats/vt_dsk_legacy.h +++ /dev/null @@ -1,18 +0,0 @@ -// license:GPL-2.0+ -// copyright-holders:Juergen Buchmueller -/********************************************************************* - - formats/vt_dsk_legacy.h - - VTech Laser/VZ disk images (legacy support) - -*********************************************************************/ - -#ifndef VT_DSK_LEGACY_H -#define VT_DSK_LEGACY_H - -#include "formats/flopimg_legacy.h" - -LEGACY_FLOPPY_OPTIONS_EXTERN(vz); - -#endif /* VT_DSK_LEGACY_H */ diff --git a/src/tools/imgtool/iflopimg.cpp b/src/tools/imgtool/iflopimg.cpp deleted file mode 100644 index 2d785c9..0000000 --- a/src/tools/imgtool/iflopimg.cpp +++ /dev/null @@ -1,324 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/********************************************************************* - - iflopimg.c - - Bridge code for Imgtool into the standard floppy code - -*********************************************************************/ - -#include "iflopimg.h" - -#include "imgtool.h" -#include "library.h" - -#include "ioprocs.h" - -#include - - -imgtoolerr_t imgtool_floppy_error(floperr_t err) -{ - switch(err) - { - case FLOPPY_ERROR_SUCCESS: - return IMGTOOLERR_SUCCESS; - - case FLOPPY_ERROR_OUTOFMEMORY: - return IMGTOOLERR_OUTOFMEMORY; - - case FLOPPY_ERROR_INVALIDIMAGE: - return IMGTOOLERR_CORRUPTIMAGE; - - case FLOPPY_ERROR_SEEKERROR: - return IMGTOOLERR_SEEKERROR; - - case FLOPPY_ERROR_UNSUPPORTED: - return IMGTOOLERR_UNIMPLEMENTED; - - default: - return IMGTOOLERR_UNEXPECTED; - } -} - - - -/********************************************************************* - Imgtool handlers -*********************************************************************/ - -struct imgtool_floppy_image -{ - floppy_image_legacy *floppy; -}; - - - - -static imgtoolerr_t imgtool_floppy_open_internal(imgtool::image &image, imgtool::stream::ptr &&stream) -{ - floperr_t ferr; - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - struct imgtool_floppy_image *fimg; - const imgtool_class *imgclass; - const struct FloppyFormat *format; - imgtoolerr_t (*open)(imgtool::image &image, imgtool::stream *f); - - fimg = (struct imgtool_floppy_image *) image.extra_bytes(); - imgclass = &image.module().imgclass; - format = (const struct FloppyFormat *) imgclass->derived_param; - open = (imgtoolerr_t (*)(imgtool::image &, imgtool::stream *)) imgtool_get_info_ptr(imgclass, IMGTOOLINFO_PTR_FLOPPY_OPEN); - - // open up the 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; - } - - if (open) - { - err = open(image, nullptr); - if (err) - goto done; - } - -done: - if (err && fimg->floppy) - { - floppy_close(fimg->floppy); - fimg->floppy = nullptr; - } - return err; -} - - - -static imgtoolerr_t imgtool_floppy_open(imgtool::image &image, imgtool::stream::ptr &&stream) -{ - return imgtool_floppy_open_internal(image, std::move(stream)); -} - - - -static imgtoolerr_t imgtool_floppy_create(imgtool::image &image, imgtool::stream::ptr &&stream, util::option_resolution *opts) -{ - floperr_t ferr; - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - struct imgtool_floppy_image *fimg; - const imgtool_class *imgclass; - const struct FloppyFormat *format; - imgtoolerr_t (*create)(imgtool::image &, imgtool::stream *, util::option_resolution *); - imgtoolerr_t (*open)(imgtool::image &, imgtool::stream *f); - - fimg = (struct imgtool_floppy_image *) image.extra_bytes(); - imgclass = &image.module().imgclass; - format = (const struct FloppyFormat *) imgclass->derived_param; - 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); - - // open up the 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; - } - - // do we have to do extra stuff when creating the image? - if (create) - { - err = create(image, nullptr, opts); - if (err) - goto done; - } - - // do we have to do extra stuff when opening the image? - if (open) - { - err = open(image, nullptr); - if (err) - goto done; - } - -done: - if (err && fimg->floppy) - { - floppy_close(fimg->floppy); - fimg->floppy = nullptr; - } - return err; -} - - - -static void imgtool_floppy_close(imgtool::image &img) -{ - floppy_close(imgtool_floppy(img)); -} - - - -static imgtoolerr_t imgtool_floppy_read_sector(imgtool::image &image, uint32_t track, uint32_t head, uint32_t sector, std::vector &buffer) -{ - floperr_t ferr; - uint32_t sector_size; - - // get the sector length - ferr = floppy_get_sector_length(imgtool_floppy(image), head, track, sector, §or_size); - if (ferr) - return imgtool_floppy_error(ferr); - - // resize the buffer accordingly - try { buffer.resize(sector_size); } - catch (std::bad_alloc const &) { return IMGTOOLERR_OUTOFMEMORY; } - - // and read the sector - ferr = floppy_read_sector(imgtool_floppy(image), head, track, sector, 0, &buffer[0], sector_size); - if (ferr) - return imgtool_floppy_error(ferr); - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t imgtool_floppy_write_sector(imgtool::image &image, uint32_t track, uint32_t head, uint32_t sector, const void *buffer, size_t len, int ddam) -{ - floperr_t ferr; - - ferr = floppy_write_sector(imgtool_floppy(image), head, track, sector, 0, buffer, len, ddam); - if (ferr) - return imgtool_floppy_error(ferr); - - return IMGTOOLERR_SUCCESS; -} - - - -static void imgtool_floppy_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info) -{ - const struct FloppyFormat *format; - imgtool_class derived_class; - - format = (const struct FloppyFormat *) imgclass->derived_param; - memset(&derived_class, 0, sizeof(derived_class)); - derived_class.get_info = imgclass->derived_get_info; - - switch(state) - { - /* --- the following bits of info are returned as 64-bit signed integers --- */ - case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES: - info->i = sizeof(struct imgtool_floppy_image) + - imgtool_get_info_int(&derived_class, IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES); - break; - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - case IMGTOOLINFO_STR_NAME: - sprintf(info->s = imgtool_temp_str(), "%s_%s", format->name, - imgtool_get_info_string(&derived_class, IMGTOOLINFO_STR_NAME)); - break; - case IMGTOOLINFO_STR_DESCRIPTION: - sprintf(info->s = imgtool_temp_str(), "%s (%s)", format->description, - imgtool_get_info_string(&derived_class, IMGTOOLINFO_STR_DESCRIPTION)); - break; - case IMGTOOLINFO_STR_FILE_EXTENSIONS: strcpy(info->s = imgtool_temp_str(), format->extensions); break; - case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC: info->p = (void*)format->param_guidelines; break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - 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_READ_SECTOR: info->read_sector = imgtool_floppy_read_sector; break; - case IMGTOOLINFO_PTR_WRITE_SECTOR: info->write_sector = imgtool_floppy_write_sector; break; - - default: imgclass->derived_get_info(imgclass, state, info); break; - } -} - - - -int imgtool_floppy_make_class(int index, imgtool_class *imgclass) -{ - const struct FloppyFormat *format; - - /* get the format */ - format = (const struct FloppyFormat *) - imgtool_get_info_ptr(imgclass, IMGTOOLINFO_PTR_FLOPPY_FORMAT); - assert(format); - if (!format[index].construct) - return false; - - imgclass->derived_get_info = imgclass->get_info; - imgclass->get_info = imgtool_floppy_get_info; - imgclass->derived_param = (void *) &format[index]; - return true; -} - - - -floppy_image_legacy *imgtool_floppy(imgtool::image &img) -{ - struct imgtool_floppy_image *fimg; - fimg = (struct imgtool_floppy_image *) img.extra_bytes(); - return fimg->floppy; -} - - - -static imgtoolerr_t imgtool_floppy_transfer_sector_tofrom_stream(imgtool::image &img, int head, int track, int sector, int offset, size_t length, imgtool::stream &f, int direction) -{ - floperr_t err; - floppy_image_legacy *floppy; - std::vector buffer; - - floppy = imgtool_floppy(img); - - buffer.resize(length); - - if (direction) - { - err = floppy_read_sector(floppy, head, track, sector, offset, &buffer[0], length); - if (err) - goto done; - f.write(&buffer[0], length); - } - else - { - f.read(&buffer[0], length); - err = floppy_write_sector(floppy, head, track, sector, offset, &buffer[0], length, 0); /* TODO: pass ddam argument from imgtool */ - if (err) - goto done; - } - - err = FLOPPY_ERROR_SUCCESS; - -done: - return imgtool_floppy_error(err); -} - - - -imgtoolerr_t imgtool_floppy_read_sector_to_stream(imgtool::image &img, int head, int track, int sector, int offset, size_t length, imgtool::stream &f) -{ - return imgtool_floppy_transfer_sector_tofrom_stream(img, head, track, sector, offset, length, f, 1); -} - - - -imgtoolerr_t imgtool_floppy_write_sector_from_stream(imgtool::image &img, int head, int track, int sector, int offset, size_t length, imgtool::stream &f) -{ - return imgtool_floppy_transfer_sector_tofrom_stream(img, head, track, sector, offset, length, f, 0); -} - - - -void *imgtool_floppy_extrabytes(imgtool::image &img) -{ - struct imgtool_floppy_image *fimg; - fimg = (struct imgtool_floppy_image *) img.extra_bytes(); - return fimg + 1; -} diff --git a/src/tools/imgtool/iflopimg.h b/src/tools/imgtool/iflopimg.h deleted file mode 100644 index 43bbb1e..0000000 --- a/src/tools/imgtool/iflopimg.h +++ /dev/null @@ -1,44 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/********************************************************************* - - iflopimg.h - - Bridge code for Imgtool into the standard floppy code - -*********************************************************************/ -#ifndef MAME_TOOLS_IMGTOOL_IFLOPIMG_H -#define MAME_TOOLS_IMGTOOL_IFLOPIMG_H - -#pragma once - -#include "library.h" - -#include "formats/flopimg_legacy.h" - - -/*************************************************************************** - - Prototypes - -***************************************************************************/ - -enum -{ - IMGTOOLINFO_PTR_FLOPPY_FORMAT = IMGTOOLINFO_PTR_CLASS_SPECIFIC, - IMGTOOLINFO_PTR_FLOPPY_OPEN, - IMGTOOLINFO_PTR_FLOPPY_CREATE -}; - -int imgtool_floppy_make_class(int index, imgtool_class *imgclass); - -floppy_image_legacy *imgtool_floppy(imgtool::image &img); -imgtoolerr_t imgtool_floppy_error(floperr_t err); - -imgtoolerr_t imgtool_floppy_read_sector_to_stream(imgtool::image &img, int head, int track, int sector, int offset, size_t length, imgtool::stream &f); -imgtoolerr_t imgtool_floppy_write_sector_from_stream(imgtool::image &img, int head, int track, int sector, int offset, size_t length, imgtool::stream &f); - - -void *imgtool_floppy_extrabytes(imgtool::image &img); - -#endif // MAME_TOOLS_IMGTOOL_IFLOPIMG_H diff --git a/src/tools/imgtool/imghd.cpp b/src/tools/imgtool/imghd.cpp deleted file mode 100644 index 09a694c..0000000 --- a/src/tools/imgtool/imghd.cpp +++ /dev/null @@ -1,250 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods, Raphael Nabet -/* - Code to interface the MESS image code with MAME's harddisk core. - - We do not support diff files as it will involve some changes in the MESS - image code. - - Raphael Nabet 2003 -*/ - -#include "imghd.h" -#include "library.h" -#include "stream.h" - -#include "harddisk.h" -#include "opresolv.h" - - -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; -} - - - -/* - imghd_create() - - Create a MAME HD image -*/ -imgtoolerr_t imghd_create(imgtool::stream &stream, uint32_t hunksize, uint32_t cylinders, uint32_t heads, uint32_t sectors, uint32_t seclen) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - chd_file chd; - 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 */ - if (hunksize > (1024 * 1024)) - { - err = IMGTOOLERR_PARAMCORRUPT; - return err; - } - if (hunksize <= 0) - hunksize = 4096; /* default value */ - - /* bail if we are read only */ - if (stream.is_read_only()) - { - err = IMGTOOLERR_READONLY; - return err; - } - - /* calculations */ - const uint64_t logicalbytes = (uint64_t)cylinders * heads * sectors * seclen; - - /* create the new hard drive */ - 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 = 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; - } - - /* alloc and zero buffer */ - std::vector cache; - cache.resize(hunksize); - memset(&cache[0], 0, hunksize); - - /* zero out every hunk */ - const int totalhunks = (logicalbytes + hunksize - 1) / hunksize; - for (int hunknum = 0; hunknum < totalhunks; hunknum++) - { - rc = chd.write_units(hunknum, &cache[0]); - if (rc) - { - err = IMGTOOLERR_WRITEERROR; - return err; - } - } - - return err; -} - - - -/* - imghd_open() - - Open stream as a MAME HD image -*/ -imgtoolerr_t imghd_open(imgtool::stream &stream, struct mess_hard_disk_file *hard_disk) -{ - std::error_condition chderr; - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - - hard_disk->hard_disk = nullptr; - - 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); - if (!hard_disk->hard_disk) - { - err = IMGTOOLERR_UNEXPECTED; - goto done; - } - hard_disk->stream = &stream; - -done: - if (err) - imghd_close(hard_disk); - return err; -} - - - -/* - imghd_close() - - Close MAME HD image -*/ -void imghd_close(struct mess_hard_disk_file *disk) -{ - if (disk->hard_disk) - { - hard_disk_close(disk->hard_disk); - disk->hard_disk = nullptr; - } - if (disk->stream) - { - delete disk->stream; - disk->stream = nullptr; - } -} - - - -/* - imghd_read() - - Read sector(s) from MAME HD image -*/ -imgtoolerr_t imghd_read(struct mess_hard_disk_file *disk, uint32_t lbasector, void *buffer) -{ - uint32_t reply = hard_disk_read(disk->hard_disk, lbasector, buffer); - return reply ? IMGTOOLERR_SUCCESS : IMGTOOLERR_READERROR; -} - - - -/* - imghd_write() - - Write sector(s) from MAME HD image -*/ -imgtoolerr_t imghd_write(struct mess_hard_disk_file *disk, uint32_t lbasector, const void *buffer) -{ - uint32_t reply = hard_disk_write(disk->hard_disk, lbasector, buffer); - return reply ? IMGTOOLERR_SUCCESS : IMGTOOLERR_WRITEERROR; -} - - - -/* - imghd_get_header() - - 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_info *reply; - reply = hard_disk_get_info(disk->hard_disk); - return reply; -} - - -static imgtoolerr_t mess_hd_image_create(imgtool::image &image, imgtool::stream::ptr &&stream, util::option_resolution *createoptions); - -enum -{ - mess_hd_createopts_blocksize = 'B', - mess_hd_createopts_cylinders = 'C', - mess_hd_createopts_heads = 'D', - mess_hd_createopts_sectors = 'E', - mess_hd_createopts_seclen = 'F' -}; - -OPTION_GUIDE_START( mess_hd_create_optionguide ) - OPTION_INT(mess_hd_createopts_blocksize, "blocksize", "Sectors Per Block" ) - OPTION_INT(mess_hd_createopts_cylinders, "cylinders", "Cylinders" ) - OPTION_INT(mess_hd_createopts_heads, "heads", "Heads" ) - OPTION_INT(mess_hd_createopts_sectors, "sectors", "Total Sectors" ) - OPTION_INT(mess_hd_createopts_seclen, "seclen", "Sector Bytes" ) -OPTION_GUIDE_END - -#define mess_hd_create_optionspecs "B1-[4]-2048;C1-[32]-65536;D1-[8]-64;E1-[128]-4096;F128/256/[512]/1024/2048/4096/8192/16384/32768/65536" - - -void hd_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info) -{ - switch(state) - { - case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "mess_hd"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "MESS hard disk image"); break; - case IMGTOOLINFO_STR_FILE_EXTENSIONS: strcpy(info->s = imgtool_temp_str(), "hd"); break; - - case IMGTOOLINFO_PTR_CREATE: info->create = mess_hd_image_create; break; - - case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE: info->createimage_optguide = &mess_hd_create_optionguide; break; - case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC: strcpy(info->s = imgtool_temp_str(), mess_hd_create_optionspecs); break; - } -} - - - -static imgtoolerr_t mess_hd_image_create(imgtool::image &image, imgtool::stream::ptr &&stream, util::option_resolution *createoptions) -{ - uint32_t blocksize, cylinders, heads, sectors, seclen; - - /* read options */ - blocksize = createoptions->lookup_int(mess_hd_createopts_blocksize); - cylinders = createoptions->lookup_int(mess_hd_createopts_cylinders); - heads = createoptions->lookup_int(mess_hd_createopts_heads); - sectors = createoptions->lookup_int(mess_hd_createopts_sectors); - seclen = createoptions->lookup_int(mess_hd_createopts_seclen); - - return imghd_create(*stream.get(), blocksize * seclen, cylinders, heads, sectors, seclen); -} diff --git a/src/tools/imgtool/imghd.h b/src/tools/imgtool/imghd.h deleted file mode 100644 index 0f96603..0000000 --- a/src/tools/imgtool/imghd.h +++ /dev/null @@ -1,50 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/**************************************************************************** - - imghd.h - - Bridge between Imgtool and CHD hard disk images - -****************************************************************************/ - -#ifndef IMGHD_H -#define IMGHD_H - -#include "imgterrs.h" - -#include "harddisk.h" - - -namespace imgtool -{ - class stream; -} - -struct mess_hard_disk_file -{ - imgtool::stream *stream; - hard_disk_file *hard_disk; - chd_file chd; -}; - - -/* create a new hard disk */ -imgtoolerr_t imghd_create(imgtool::stream &stream, uint32_t blocksize, uint32_t cylinders, uint32_t heads, uint32_t sectors, uint32_t seclen); - -/* opens a hard disk given an Imgtool stream */ -imgtoolerr_t imghd_open(imgtool::stream &stream, mess_hard_disk_file *hard_disk); - -/* close a hard disk */ -void imghd_close(struct mess_hard_disk_file *disk); - -/* reads data from a hard disk */ -imgtoolerr_t imghd_read(struct mess_hard_disk_file *disk, uint32_t lbasector, void *buffer); - -/* writes data to a hard disk */ -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); - -#endif /* IMGHD_H */ diff --git a/src/tools/imgtool/imgterrs.cpp b/src/tools/imgtool/imgterrs.cpp deleted file mode 100644 index 9018ed7..0000000 --- a/src/tools/imgtool/imgterrs.cpp +++ /dev/null @@ -1,56 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/*************************************************************************** - - imgterrs.c - - Imgtool errors - -***************************************************************************/ - -#include "imgterrs.h" - -#include -#include - -static const char *const msgs[] = -{ - "Out of memory", - "Unexpected error", - "Argument too long", - "Read error", - "Write error", - "Image is read only", - "Corrupt image", - "Corrupt file", - "Corrupt directory", - "File not found", - "Unrecognized format", - "Not implemented", - "Parameter too small", - "Parameter too large", - "Missing parameter not found", - "Inappropriate parameter", - "Invalid parameter", - "Bad file name", - "Out of space on image", - "Input past end of file", - "Cannot specify path", - "Invalid path", - "Path not found", - "Directory not empty", - "Seek error", - "File system does not support forks", - "Fork not found", - "Invalid partition" -}; - - - -const char *imgtool_error(imgtoolerr_t err) -{ - err = (imgtoolerr_t)(ERRORCODE(err) - 1); - assert(err >= 0); - assert(err < std::size(msgs)); - return msgs[err]; -} diff --git a/src/tools/imgtool/imgterrs.h b/src/tools/imgtool/imgterrs.h deleted file mode 100644 index 1cdafb6..0000000 --- a/src/tools/imgtool/imgterrs.h +++ /dev/null @@ -1,70 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/*************************************************************************** - - imgterrs.h - - Imgtool errors - -***************************************************************************/ - -#ifndef IMGTERRS_H -#define IMGTERRS_H - -/* Error codes */ -enum imgtoolerr_t -{ - IMGTOOLERR_SUCCESS, - IMGTOOLERR_OUTOFMEMORY, - IMGTOOLERR_UNEXPECTED, - IMGTOOLERR_BUFFERTOOSMALL, - IMGTOOLERR_READERROR, - IMGTOOLERR_WRITEERROR, - IMGTOOLERR_READONLY, - IMGTOOLERR_CORRUPTIMAGE, - IMGTOOLERR_CORRUPTFILE, - IMGTOOLERR_CORRUPTDIR, - IMGTOOLERR_FILENOTFOUND, - IMGTOOLERR_MODULENOTFOUND, - IMGTOOLERR_UNIMPLEMENTED, - IMGTOOLERR_PARAMTOOSMALL, - IMGTOOLERR_PARAMTOOLARGE, - IMGTOOLERR_PARAMNEEDED, - IMGTOOLERR_PARAMNOTNEEDED, - IMGTOOLERR_PARAMCORRUPT, - IMGTOOLERR_BADFILENAME, - IMGTOOLERR_NOSPACE, - IMGTOOLERR_INPUTPASTEND, - IMGTOOLERR_CANNOTUSEPATH, - IMGTOOLERR_INVALIDPATH, - IMGTOOLERR_PATHNOTFOUND, - IMGTOOLERR_DIRNOTEMPTY, - IMGTOOLERR_SEEKERROR, - IMGTOOLERR_NOFORKS, - IMGTOOLERR_FORKNOTFOUND, - IMGTOOLERR_INVALIDPARTITION -}; - - - -/* These error codes are actually modifiers that make it easier to distinguish - * the cause of an error - * - * Note - drivers should not use these modifiers - */ -#define IMGTOOLERR_SRC_MODULE 0x1000 -#define IMGTOOLERR_SRC_FUNCTIONALITY 0x2000 -#define IMGTOOLERR_SRC_IMAGEFILE 0x3000 -#define IMGTOOLERR_SRC_FILEONIMAGE 0x4000 -#define IMGTOOLERR_SRC_NATIVEFILE 0x5000 - -#define ERRORCODE(err) ((err) & 0x0fff) -#define ERRORSOURCE(err) ((err) & 0xf000) -#define ERRORPARAM(err) (((err) & 0xf0000) / 0x10000) - -#define PARAM_TO_ERROR(errcode, param) ((errcode) | ((param) * 0x10000)) - - -const char *imgtool_error(imgtoolerr_t err); - -#endif /* IMGTERRS_H */ diff --git a/src/tools/imgtool/imgtool.cpp b/src/tools/imgtool/imgtool.cpp deleted file mode 100644 index c407b55..0000000 --- a/src/tools/imgtool/imgtool.cpp +++ /dev/null @@ -1,2375 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/*************************************************************************** - - imgtool.cpp - - Core code for Imgtool - -***************************************************************************/ - -#include "imgtool.h" -#include "charconv.h" -#include "filter.h" -#include "library.h" -#include "modules.h" - -#include "formats/imageutl.h" - -#include "corefile.h" -#include "corestr.h" -#include "opresolv.h" - -#include -#include -#include -#include - - - -/*************************************************************************** - GLOBALS -***************************************************************************/ - -static std::unique_ptr global_imgtool_library; - -static int global_omit_untested; -static void (*global_warn)(const char *message); - - -void CLIB_DECL ATTR_PRINTF(1,2) logerror(const char *format, ...) -{ - va_list arg; - va_start(arg, format); - vprintf(format, arg); - va_end(arg); -} - -/*************************************************************************** - - Imgtool initialization and basics - -***************************************************************************/ - -//------------------------------------------------- -// rtrim -//------------------------------------------------- - -void rtrim(char *buf) -{ - size_t buflen; - char *s; - - buflen = strlen(buf); - if (buflen) - { - for (s = &buf[buflen-1]; s >= buf && (*s >= '\0') && isspace(*s); s--) - *s = '\0'; - } -} - - -//------------------------------------------------- -// strncpyz -//------------------------------------------------- - -char *strncpyz(char *dest, const char *source, size_t len) -{ - char *s; - if (len) { - s = strncpy(dest, source, len - 1); - dest[len-1] = '\0'; - } - else { - s = dest; - } - return s; -} - - -//------------------------------------------------- -// extract_padded_string -//------------------------------------------------- - -static std::string extract_padded_string(const char *source, size_t len, char pad) -{ - while ((len > 0) && (source[len - 1] == pad)) - len--; - - return std::string(source, len); -} - - -//------------------------------------------------- -// extract_padded_filename - this is a common -// enough scenario that it is justified to have -// this in common code -//------------------------------------------------- - -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, pad); - std::string extension = extract_padded_string(source + filename_length, extension_length, pad); - return extension.empty() ? filename : filename + "." + extension; -} - - -//------------------------------------------------- -// markerrorsource - marks where an error source -//------------------------------------------------- - -static imgtoolerr_t markerrorsource(imgtoolerr_t err) -{ - switch(err) - { - case IMGTOOLERR_OUTOFMEMORY: - case IMGTOOLERR_UNEXPECTED: - case IMGTOOLERR_BUFFERTOOSMALL: - /* Do nothing */ - break; - - case IMGTOOLERR_FILENOTFOUND: - case IMGTOOLERR_BADFILENAME: - err = imgtoolerr_t(err | IMGTOOLERR_SRC_FILEONIMAGE); - break; - - default: - err = imgtoolerr_t(err | IMGTOOLERR_SRC_IMAGEFILE); - break; - } - return err; -} - -//------------------------------------------------- -// internal_error - debug function for raising -// internal errors -//------------------------------------------------- - -static void internal_error(const imgtool_module *module, const char *message) -{ -#ifdef MAME_DEBUG - printf("%s: %s\n", module->name.c_str(), message); -#endif -} - - -//------------------------------------------------- -// imgtool_init - initializes the imgtool core -//------------------------------------------------- - -void imgtool_init(bool omit_untested, void (*warn)(const char *message)) -{ - imgtoolerr_t err; - err = imgtool_create_canonical_library(omit_untested, global_imgtool_library); - assert(err == IMGTOOLERR_SUCCESS); - if (err == IMGTOOLERR_SUCCESS) - { - global_imgtool_library->sort(imgtool::library::sort_type::DESCRIPTION); - } - global_omit_untested = omit_untested; - global_warn = warn; -} - - - -//------------------------------------------------- -// imgtool_exit - closes out the imgtool core -//------------------------------------------------- - -void imgtool_exit(void) -{ - if (global_imgtool_library) - global_imgtool_library.reset(); - - global_warn = nullptr; -} - - - -//------------------------------------------------- -// imgtool_find_module - looks up a module -//------------------------------------------------- - -const imgtool_module *imgtool_find_module(const std::string &modulename) -{ - return global_imgtool_library->findmodule(modulename); -} - - -//------------------------------------------------- -// imgtool_find_module - looks up a module -//------------------------------------------------- - -const imgtool::library::modulelist &imgtool_get_modules() -{ - return global_imgtool_library->modules(); -} - - -//------------------------------------------------- -// imgtool_get_module_features - retrieves a -// structure identifying this module's features -// associated with an image -//------------------------------------------------- - -imgtool_module_features imgtool_get_module_features(const imgtool_module *module) -{ - imgtool_module_features features; - memset(&features, 0, sizeof(features)); - - if (module->create) - features.supports_create = 1; - if (module->open) - features.supports_open = 1; - if (module->read_sector) - features.supports_readsector = 1; - if (module->write_sector) - features.supports_writesector = 1; - return features; -} - - - -//------------------------------------------------- -// imgtool_warn - issues a warning -//------------------------------------------------- - -void imgtool_warn(const char *format, ...) -{ - va_list va; - char buffer[2000]; - - if (global_warn) - { - va_start(va, format); - vsprintf(buffer, format, va); - va_end(va); - global_warn(buffer); - } -} - - - -//------------------------------------------------- -// evaluate_module - evaluates a single file to -// determine what module can best handle a file -//------------------------------------------------- - -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; - - err = imgtool::image::open(module, fname, OSD_FOPEN_READ, image); - if (err) - goto done; - - if (image) - { - current_result = module->open_is_strict ? 0.9 : 0.5; - - err = imgtool::partition::open(*image, 0, partition); - if (err) - goto done; - - err = imgtool::directory::open(*partition, "", imageenum); - if (err) - goto done; - - memset(&ent, 0, sizeof(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; - } - -done: - if (ERRORCODE(err) == IMGTOOLERR_CORRUPTIMAGE) - err = IMGTOOLERR_SUCCESS; - return err; -} - - -//------------------------------------------------- -// identify_file - attempts to determine the module -// for any given image -//------------------------------------------------- - -imgtoolerr_t imgtool::image::identify_file(const char *fname, imgtool_module **modules, size_t count) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - imgtool::library &library = *global_imgtool_library.get(); - imgtool_module *insert_module; - imgtool_module *temp_module; - size_t i = 0; - const char *extension; - float val, temp_val; - std::unique_ptr values; - - if (count <= 0) - return IMGTOOLERR_UNEXPECTED; - - for (i = 0; i < count; i++) - modules[i] = nullptr; - if (count > 1) - count--; /* null terminate */ - - try { values = std::make_unique(count); } - catch (std::bad_alloc const &) { return IMGTOOLERR_OUTOFMEMORY; } - for (i = 0; i < count; i++) - values[i] = 0.0; - - /* figure out the file extension, if any */ - extension = strrchr(fname, '.'); - if (extension) - extension++; - - /* iterate through all modules */ - for (const auto &module : library.modules()) - { - if (!extension || image_find_extension(module->extensions.c_str(), extension)) - { - err = evaluate_module(fname, module.get(), val); - if (err) - return err; - - insert_module = module.get(); - for (i = 0; (val > 0.0f) && (i < count); i++) - { - if (val > values[i]) - { - temp_val = values[i]; - temp_module = modules[i]; - values[i] = val; - modules[i] = insert_module; - val = temp_val; - insert_module = temp_module; - } - } - } - } - - if (!modules[0]) - return imgtoolerr_t(IMGTOOLERR_MODULENOTFOUND | IMGTOOLERR_SRC_IMAGEFILE); - - return IMGTOOLERR_SUCCESS; -} - - - -//------------------------------------------------- -// get_geometry - gets the geometry -// of an image; note that this may disagree with -// particular sectors; this is a common copy -// protection scheme -//------------------------------------------------- - -imgtoolerr_t imgtool::image::get_geometry(uint32_t *tracks, uint32_t *heads, uint32_t *sectors) -{ - uint32_t dummy; - - /* some sanitization, to make the callbacks easier to implement */ - if (!tracks) - tracks = &dummy; - if (!heads) - heads = &dummy; - if (!sectors) - sectors = &dummy; - *tracks = 0; - *heads = 0; - *sectors = 0; - - /* implemented? */ - if (!module().get_geometry) - return imgtoolerr_t(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - return module().get_geometry(*this, tracks, heads, sectors); -} - - - -//------------------------------------------------- -// read_sector - reads a sector on an image -//------------------------------------------------- - -imgtoolerr_t imgtool::image::read_sector(uint32_t track, uint32_t head, - uint32_t sector, std::vector &buffer) -{ - // implemented? - if (!module().read_sector) - return imgtoolerr_t(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - return module().read_sector(*this, track, head, sector, buffer); -} - - - -//------------------------------------------------- -// write_sector - writes a sector on an image -//------------------------------------------------- - -imgtoolerr_t imgtool::image::write_sector(uint32_t track, uint32_t head, - uint32_t sector, const void *buffer, size_t len) -{ - // implemented? - if (!module().write_sector) - return imgtoolerr_t(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - return module().write_sector(*this, track, head, sector, buffer, len); -} - - - -//------------------------------------------------- -// get_block_size - gets the size of a standard -// block on an image -//------------------------------------------------- - -imgtoolerr_t imgtool::image::get_block_size(uint32_t &length) -{ - // implemented? - if (module().block_size == 0) - return imgtoolerr_t(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - length = module().block_size; - return IMGTOOLERR_SUCCESS; -} - - -//------------------------------------------------- -// read_block - reads a standard block on an image -//------------------------------------------------- - -imgtoolerr_t imgtool::image::read_block(uint64_t block, void *buffer) -{ - // implemented? - if (!module().read_block) - return imgtoolerr_t(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - return module().read_block(*this, buffer, block); -} - - -//------------------------------------------------- -// write_block - writes a standard block on an image -//------------------------------------------------- - -imgtoolerr_t imgtool::image::write_block(uint64_t block, const void *buffer) -{ - // implemented? - if (!module().write_block) - return imgtoolerr_t(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - return module().write_block(*this, buffer, block); -} - - -//------------------------------------------------- -// clear_block - clears a standard block on an image -//------------------------------------------------- - -imgtoolerr_t imgtool::image::clear_block(uint64_t block, uint8_t data) -{ - imgtoolerr_t err; - uint8_t *block_data = nullptr; - uint32_t length; - - err = get_block_size(length); - if (err) - goto done; - - block_data = (uint8_t*)malloc(length); - if (!block_data) - { - err = (imgtoolerr_t)IMGTOOLERR_OUTOFMEMORY; - goto done; - } - memset(block_data, data, length); - - err = write_block(block, block_data); - if (err) - goto done; - -done: - if (block_data) - free(block_data); - return err; -} - - -//------------------------------------------------- -// list_partitions - lists the partitions on an image -//------------------------------------------------- - -imgtoolerr_t imgtool::image::list_partitions(std::vector &partitions) -{ - imgtoolerr_t err; - - // clear out partitions first - partitions.clear(); - - // implemented? - if (module().list_partitions) - { - // if so, call the module's callback - err = module().list_partitions(*this, partitions); - if (err) - return err; - } - else - { - // default implementation - partitions.emplace_back(module().imgclass, 0, ~0); - } - return IMGTOOLERR_SUCCESS; -} - - -/*************************************************************************** - - Imgtool partition management - -***************************************************************************/ - -//------------------------------------------------- -// imgtool::partition ctor -//------------------------------------------------- - -imgtool::partition::partition(imgtool::image &image, const imgtool_class &imgclass, int partition_index, uint64_t base_block, uint64_t block_count) - : m_image(image) - , m_base_block(base_block) - , m_block_count(block_count) - , m_imgclass(imgclass) -{ - // does this partition type have extra bytes? - size_t extra_bytes_size = imgtool_get_info_int(&imgclass, IMGTOOLINFO_INT_PARTITION_EXTRA_BYTES); - if (extra_bytes_size > 0) - { - m_extra_bytes = std::make_unique(extra_bytes_size); - memset(m_extra_bytes.get(), 0, sizeof(m_extra_bytes.get()[0]) * extra_bytes_size); - } - - m_directory_extra_bytes = imgtool_get_info_int(&imgclass, IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES); - m_path_separator = (char)imgtool_get_info_int(&imgclass, IMGTOOLINFO_INT_PATH_SEPARATOR); - m_alternate_path_separator = (char)imgtool_get_info_int(&imgclass, IMGTOOLINFO_INT_ALTERNATE_PATH_SEPARATOR); - m_prefer_ucase = imgtool_get_info_int(&imgclass, IMGTOOLINFO_INT_PREFER_UCASE) ? 1 : 0; - m_supports_creation_time = imgtool_get_info_int(&imgclass, IMGTOOLINFO_INT_SUPPORTS_CREATION_TIME) ? 1 : 0; - m_supports_lastmodified_time = imgtool_get_info_int(&imgclass, IMGTOOLINFO_INT_SUPPORTS_LASTMODIFIED_TIME) ? 1 : 0; - m_supports_bootblock = imgtool_get_info_int(&imgclass, IMGTOOLINFO_INT_SUPPORTS_BOOTBLOCK) ? 1 : 0; - m_begin_enum = (imgtoolerr_t(*)(imgtool::directory &, const char *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_BEGIN_ENUM); - m_next_enum = (imgtoolerr_t(*)(imgtool::directory &, imgtool_dirent &)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_NEXT_ENUM); - m_close_enum = (void(*)(imgtool::directory &)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_CLOSE_ENUM); - m_free_space = (imgtoolerr_t(*)(imgtool::partition &, uint64_t *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_FREE_SPACE); - m_read_file = (imgtoolerr_t(*)(imgtool::partition &, const char *, const char *, imgtool::stream &)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_READ_FILE); - m_write_file = (imgtoolerr_t(*)(imgtool::partition &, const char *, const char *, imgtool::stream &, util::option_resolution *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_WRITE_FILE); - m_delete_file = (imgtoolerr_t(*)(imgtool::partition &, const char *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_DELETE_FILE); - m_list_forks = (imgtoolerr_t(*)(imgtool::partition &, const char *, std::vector &forks)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_LIST_FORKS); - m_create_dir = (imgtoolerr_t(*)(imgtool::partition &, const char *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_CREATE_DIR); - m_delete_dir = (imgtoolerr_t(*)(imgtool::partition &, const char *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_DELETE_DIR); - m_list_attrs = (imgtoolerr_t(*)(imgtool::partition &, const char *, uint32_t *, size_t)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_LIST_ATTRS); - m_get_attrs = (imgtoolerr_t(*)(imgtool::partition &, const char *, const uint32_t *, imgtool_attribute *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_GET_ATTRS); - 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_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); - if (writefile_optspec) - m_writefile_optspec.assign(writefile_optspec); - - // mask out if writing is untested - if (global_omit_untested && imgtool_get_info_int(&imgclass, IMGTOOLINFO_INT_WRITING_UNTESTED)) - { - m_write_file = nullptr; - m_delete_file = nullptr; - m_create_dir = nullptr; - m_delete_dir = nullptr; - m_writefile_optguide = nullptr; - m_writefile_optspec = nullptr; - } -} - - -//------------------------------------------------- -// imgtool::partition dtor -//------------------------------------------------- - -imgtool::partition::~partition() -{ -} - - -//------------------------------------------------- -// open - opens a partition -//------------------------------------------------- - -imgtoolerr_t imgtool::partition::open(imgtool::image &image, int partition_index, imgtool::partition::ptr &partition) -{ - imgtoolerr_t err = (imgtoolerr_t)IMGTOOLERR_SUCCESS; - imgtool::partition::ptr p; - std::vector partitions; - imgtoolerr_t (*open_partition)(imgtool::partition &partition, uint64_t first_block, uint64_t block_count); - - // list the partitions - err = image.list_partitions(partitions); - if (err) - return err; - - // is this an invalid index? - if ((partition_index < 0) || (partition_index >= partitions.size()) || (!partitions[partition_index].imgclass().get_info && !partitions[partition_index].imgclass().derived_get_info)) - return IMGTOOLERR_INVALIDPARTITION; - - // use this partition - const imgtool_class &imgclass(partitions[partition_index].imgclass()); - uint64_t base_block = partitions[partition_index].base_block(); - uint64_t block_count = partitions[partition_index].block_count(); - - // allocate the new partition object - try { p = std::make_unique(image, imgclass, partition_index, base_block, block_count); } - catch (std::bad_alloc const &) - { - err = (imgtoolerr_t)IMGTOOLERR_OUTOFMEMORY; - goto done; - } - - // call the partition open function, if present - open_partition = (imgtoolerr_t (*)(imgtool::partition &, uint64_t, uint64_t)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_OPEN_PARTITION); - if (open_partition) - { - /* we have an open partition function */ - err = (*open_partition)(*p, base_block, block_count); - if (err) - goto done; - } - -done: - if (!err) - partition = std::move(p); - else - partition.reset(); - return err; -} - - - -/*************************************************************************** - - Imgtool partition operations - -***************************************************************************/ - -//------------------------------------------------- -// get_attribute_name - retrieves the human readable -// name for an attribute -//------------------------------------------------- - -void imgtool::partition::get_attribute_name(uint32_t attribute, const imgtool_attribute *attr_value, - char *buffer, size_t buffer_len) -{ - imgtoolerr_t err = (imgtoolerr_t)IMGTOOLERR_UNIMPLEMENTED; - - buffer[0] = '\0'; - - if (attr_value) - { - if (m_attr_name) - err = m_attr_name(attribute, attr_value, buffer, buffer_len); - - if (err == (imgtoolerr_t)IMGTOOLERR_UNIMPLEMENTED) - { - switch(attribute & 0xF0000) - { - case IMGTOOLATTR_INT_FIRST: - snprintf(buffer, buffer_len, "%d", (int) attr_value->i); - break; - } - } - } - else - { - switch(attribute) - { - case IMGTOOLATTR_INT_MAC_TYPE: - snprintf(buffer, buffer_len, "File type"); - break; - case IMGTOOLATTR_INT_MAC_CREATOR: - snprintf(buffer, buffer_len, "File creator"); - break; - case IMGTOOLATTR_INT_MAC_FINDERFLAGS: - snprintf(buffer, buffer_len, "Finder flags"); - break; - case IMGTOOLATTR_INT_MAC_COORDX: - snprintf(buffer, buffer_len, "X coordinate"); - break; - case IMGTOOLATTR_INT_MAC_COORDY: - snprintf(buffer, buffer_len, "Y coordinate"); - break; - case IMGTOOLATTR_INT_MAC_FINDERFOLDER: - snprintf(buffer, buffer_len, "Finder folder"); - break; - case IMGTOOLATTR_INT_MAC_ICONID: - snprintf(buffer, buffer_len, "Icon ID"); - break; - case IMGTOOLATTR_INT_MAC_SCRIPTCODE: - snprintf(buffer, buffer_len, "Script code"); - break; - case IMGTOOLATTR_INT_MAC_EXTENDEDFLAGS: - snprintf(buffer, buffer_len, "Extended flags"); - break; - case IMGTOOLATTR_INT_MAC_COMMENTID: - snprintf(buffer, buffer_len, "Comment ID"); - break; - case IMGTOOLATTR_INT_MAC_PUTAWAYDIRECTORY: - snprintf(buffer, buffer_len, "Putaway directory"); - break; - case IMGTOOLATTR_TIME_CREATED: - snprintf(buffer, buffer_len, "Creation time"); - break; - case IMGTOOLATTR_TIME_LASTMODIFIED: - snprintf(buffer, buffer_len, "Last modified time"); - break; - } - } -} - - -//------------------------------------------------- -// test_imgtool_datetime - unit test for imgtool::datetime -//------------------------------------------------- - -static bool test_imgtool_datetime(int second, int minute, int hour, int day_of_month, int month, int year) -{ - bool error = false; - - util::arbitrary_datetime t; - t.second = second; - t.minute = minute; - t.hour = hour; - t.day_of_month = day_of_month; - t.month = month; - t.year = year; - - imgtool::datetime dt(imgtool::datetime::datetime_type::GMT, t); - std::tm t2 = dt.gmtime(); - - if (t2.tm_sec != second) - { - util::stream_format(std::wcerr, L"test_imgtool_datetime(): Expected t2.tm_sec to be %d, instead got %d\n", second, t2.tm_sec); - error = true; - } - if (t2.tm_min != minute) - { - util::stream_format(std::wcerr, L"test_imgtool_datetime(): Expected t2.tm_min to be %d, instead got %d\n", minute, t2.tm_min); - error = true; - } - if (t2.tm_hour != hour) - { - util::stream_format(std::wcerr, L"test_imgtool_datetime(): Expected t2.tm_hour to be %d, instead got %d\n", hour, t2.tm_hour); - error = true; - } - if (t2.tm_mday != day_of_month) - { - util::stream_format(std::wcerr, L"test_imgtool_datetime(): Expected t2.tm_mday to be %d, instead got %d\n", day_of_month, t2.tm_mday); - error = true; - } - if (t2.tm_mon != month - 1) - { - util::stream_format(std::wcerr, L"test_imgtool_datetime(): Expected t2.tm_mon to be %d, instead got %d\n", month - 1, t2.tm_mon); - error = true; - } - if (t2.tm_year != year - 1900) - { - util::stream_format(std::wcerr, L"test_imgtool_datetime(): Expected t2.tm_mon to be %d, instead got %d\n", year - 1900, t2.tm_year); - error = true; - } - return error; -} - - -//------------------------------------------------- -// test_imgtool_datetime - unit tests for imgtool::datetime -//------------------------------------------------- - -static bool test_imgtool_datetime() -{ - bool error = false; - - // various test cases for imgtool::datetime - if (test_imgtool_datetime(34, 23, 12, 18, 3, 1993)) // March 18th, 1993 12:23:34 - error = true; - if (test_imgtool_datetime(0, 20, 16, 25, 12, 1976)) // December 25th, 1976 16:20:00 - error = true; - - return error; -} - - -//------------------------------------------------- -// imgtool_validitychecks - checks the validity -// of the imgtool modules -//------------------------------------------------- - -bool imgtool_validitychecks(void) -{ - bool error = false; - imgtoolerr_t err = (imgtoolerr_t)IMGTOOLERR_SUCCESS; - imgtool_module_features features; - int created_library = false; - - // various test cases for imgtool::datetime - if (test_imgtool_datetime()) - error = true; - - if (!global_imgtool_library) - { - imgtool_init(false, nullptr); - created_library = true; - } - - for (const auto &module : global_imgtool_library->modules()) - { - features = imgtool_get_module_features(module.get()); - - if (module->name.empty()) - { - util::stream_format(std::wcerr, L"imgtool module has null 'name'\n"); - error = true; - } - 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.empty()) - { - util::stream_format(std::wcerr, L"imgtool module %s has null 'extensions'\n", wstring_from_utf8(module->extensions)); - error = true; - } - -#if 0 - /* sanity checks on modules that do not support directories */ - if (!module->path_separator) - { - if (module->alternate_path_separator) - { - util::stream_format(std::wcerr, L"imgtool module %s specified alternate_path_separator but not path_separator\n", wstring_from_utf8(module->name)); - error = true; - } - if (module->initial_path_separator) - { - util::stream_format(std::wcerr, L"imgtool module %s specified initial_path_separator without directory support\n", wstring_from_utf8(module->name)); - error = true; - } - if (module->create_dir) - { - util::stream_format(std::wcerr, L"imgtool module %s implements create_dir without directory support\n", wstring_from_utf8(module->name)); - error = true; - } - if (module->delete_dir) - { - util::stream_format(std::wcerr, L"imgtool module %s implements delete_dir without directory support\n", wstring_from_utf8(module->name)); - error = true; - } - } -#endif - - /* sanity checks on creation options */ - 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.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)); - error = true; - } - - if (module->createimage_optguide && !module->createimage_optspec.empty()) - { - auto resolution = std::make_unique(*module->createimage_optguide); - resolution->set_specification(module->createimage_optspec.c_str()); - } - } - } - - if (created_library) - imgtool_exit(); - if (err) - { - util::stream_format(std::wcerr, L"imgtool: %s\n", wstring_from_utf8(imgtool_error(err))); - error = true; - } - return error; -} - - - -/*------------------------------------------------- - imgtool_temp_str - provides a temporary string - buffer used for string passing --------------------------------------------------*/ - -char *imgtool_temp_str(void) -{ - static int index; - static char temp_string_pool[32][256]; - return temp_string_pool[index++ % std::size(temp_string_pool)]; -} - - - -/*************************************************************************** - - Image handling functions - -***************************************************************************/ - -imgtoolerr_t imgtool::image::internal_open(const imgtool_module *module, const std::string &filename, - int read_or_write, util::option_resolution *createopts, imgtool::image::ptr &outimg) -{ - imgtoolerr_t err; - imgtool::stream::ptr stream; - imgtool::image::ptr image; - - outimg.reset(); - - // is the requested functionality implemented? - if ((read_or_write == OSD_FOPEN_RW_CREATE) ? !module->create : !module->open) - { - err = imgtoolerr_t(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - goto done; - } - - // open the stream - stream = imgtool::stream::open(filename, read_or_write); - if (!stream) - { - err = imgtoolerr_t(IMGTOOLERR_FILENOTFOUND | IMGTOOLERR_SRC_IMAGEFILE); - goto done; - } - - // setup the image structure - try { image = std::make_unique(*module); } - catch (std::bad_alloc const &) - { - err = imgtoolerr_t(IMGTOOLERR_OUTOFMEMORY); - goto done; - } - - // actually call create or open - err = (read_or_write == OSD_FOPEN_RW_CREATE) - ? module->create(*image, std::move(stream), createopts) - : module->open(*image, std::move(stream)); - if (err) - { - err = markerrorsource(err); - goto done; - } - - // we've succeeded - set the output image, and record that - // we are "okay to close" - image->m_okay_to_close = true; - outimg = std::move(image); - -done: - return err; -} - - -//------------------------------------------------- -// open - open an image -//------------------------------------------------- - -imgtoolerr_t imgtool::image::open(const imgtool_module *module, const std::string &filename, int read_or_write, ptr &outimg) -{ - read_or_write = read_or_write ? OSD_FOPEN_RW : OSD_FOPEN_READ; - return internal_open(module, filename, read_or_write, nullptr, outimg); -} - - -//------------------------------------------------- -// imgtool::image::open_byname - open an image -//------------------------------------------------- - -imgtoolerr_t imgtool::image::open(const std::string &modulename, const std::string &filename, int read_or_write, ptr &outimg) -{ - const imgtool_module *module; - - module = imgtool_find_module(modulename); - if (!module) - return imgtoolerr_t(IMGTOOLERR_MODULENOTFOUND | IMGTOOLERR_SRC_MODULE); - - return open(module, filename, read_or_write, outimg); -} - - -//------------------------------------------------- -// imgtool::image::image -//------------------------------------------------- - -imgtool::image::image(const imgtool_module &module) - : m_module(module) - , m_okay_to_close(false) -{ - if (module.image_extra_bytes > 0) - { - m_extra_bytes = std::make_unique(module.image_extra_bytes); - std::fill_n(&m_extra_bytes[0], module.image_extra_bytes, 0); - } - -} - - -//------------------------------------------------- -// imgtool::image::~image -//------------------------------------------------- - -imgtool::image::~image() -{ - if (m_okay_to_close && module().close) - module().close(*this); -} - - -//------------------------------------------------- -// create - creates an image -//------------------------------------------------- - -imgtoolerr_t imgtool::image::create(const imgtool_module *module, const std::string &filename, - util::option_resolution *opts, ptr &image) -{ - std::unique_ptr alloc_resolution; - - /* allocate dummy options if necessary */ - if (!opts && module->createimage_optguide) - { - try { alloc_resolution.reset(new util::option_resolution(*module->createimage_optguide)); } - catch (...) { return (imgtoolerr_t)IMGTOOLERR_OUTOFMEMORY; } - - if (!module->createimage_optspec.empty()) - alloc_resolution->set_specification(module->createimage_optspec.c_str()); - - opts = alloc_resolution.get(); - } - - return internal_open(module, filename, OSD_FOPEN_RW_CREATE, opts, image); -} - - -//------------------------------------------------- -// create - creates an image -//------------------------------------------------- - -imgtoolerr_t imgtool::image::create(const std::string &modulename, const std::string &filename, util::option_resolution *opts, ptr &image) -{ - const imgtool_module *module; - - module = imgtool_find_module(modulename); - if (!module) - return imgtoolerr_t(IMGTOOLERR_MODULENOTFOUND | IMGTOOLERR_SRC_MODULE); - - return create(module, filename, opts, image); -} - - -//------------------------------------------------- -// create - creates an image -//------------------------------------------------- - -imgtoolerr_t imgtool::image::create(const imgtool_module *module, const std::string &filename, - util::option_resolution *opts) -{ - std::unique_ptr image; - return create(module, filename, opts, image); -} - - -//------------------------------------------------- -// create - creates an image -//------------------------------------------------- - -imgtoolerr_t imgtool::image::create(const std::string &modulename, const std::string &filename, util::option_resolution *opts) -{ - std::unique_ptr image; - return create(modulename, filename, opts, image); -} - - -//------------------------------------------------- -// info - returns format specific information about an image -//------------------------------------------------- - -std::string imgtool::image::info() -{ - std::string string; - if (module().info) - { - std::stringstream stream; - module().info(*this, stream); - string = stream.str(); - } - return string; -} - - - -#define PATH_MUSTBEDIR 0x00000001 -#define PATH_LEAVENULLALONE 0x00000002 -#define PATH_CANBEBOOTBLOCK 0x00000004 - -//------------------------------------------------- -// partition::canonicalize_path - normalizes a path string -// into a NUL delimited list -//------------------------------------------------- - -imgtoolerr_t imgtool::partition::canonicalize_path(uint32_t flags, const char *path, std::string &result) -{ - imgtoolerr_t err = (imgtoolerr_t)IMGTOOLERR_SUCCESS; - - // is this path NULL? if so, is that ignored? - if (!path && (flags & PATH_LEAVENULLALONE)) - return IMGTOOLERR_SUCCESS; - - // is this the special filename for bootblocks? - if (path == FILENAME_BOOTBLOCK) - { - if (!(flags & PATH_CANBEBOOTBLOCK)) - err = (imgtoolerr_t)IMGTOOLERR_UNEXPECTED; - else if (!m_supports_bootblock) - err = (imgtoolerr_t)IMGTOOLERR_FILENOTFOUND; - return err; - } - - // normalize the path into the native character set - std::string converted_path; - imgtool::charconverter * const converter = reinterpret_cast(get_info_ptr(IMGTOOLINFO_PTR_CHARCONVERTER)); - if (converter) - { - converted_path = converter->from_utf8(path); - path = converted_path.c_str(); - } - - if (m_path_separator == '\0') - { - if (flags & PATH_MUSTBEDIR) - { - // do we specify a path when paths are not supported? */ - if (path && *path) - return imgtoolerr_t(IMGTOOLERR_CANNOTUSEPATH | IMGTOOLERR_SRC_FUNCTIONALITY); - - result = ""; /* normalize empty path */ - } - else - { - // simple passthrough - result = path; - } - } - else - { - const char *s = path ? path : ""; - - // allocate space for a new canonical path - std::ostringstream stream; - - // copy the path - bool in_path_separator = true; - size_t i = 0; - do - { - if ((s[i] != '\0') && (s[i] != m_path_separator) && (s[i] != m_alternate_path_separator)) - { - stream << s[i]; - in_path_separator = false; - } - else if (!in_path_separator) - { - stream << '\0'; - in_path_separator = true; - } - } - while(s[i++] != '\0'); - stream << '\0' << '\0'; - result = stream.str(); - } - - return IMGTOOLERR_SUCCESS; -} - - -//------------------------------------------------- -// partition::canonicalize_fork -//------------------------------------------------- - -imgtoolerr_t imgtool::partition::canonicalize_fork(const char **fork) -{ - // does this module support forks? - if (m_list_forks) - { - // this module supports forks; make sure that fork is non-NULL - if (!*fork) - *fork = ""; - } - else - { - // this module does not support forks; make sure that fork is NULL - if (*fork) - return IMGTOOLERR_NOFORKS; - } - return IMGTOOLERR_SUCCESS; -} - - -//------------------------------------------------- -// partition::get_directory_entry - retrieves -// the nth directory entry within a partition -//------------------------------------------------- - -imgtoolerr_t imgtool::partition::get_directory_entry(const char *path, int index, imgtool_dirent &ent) -{ - imgtoolerr_t err; - imgtool::directory::ptr imgenum; - - if (index < 0) - { - err = (imgtoolerr_t)IMGTOOLERR_PARAMTOOSMALL; - goto done; - } - - err = imgtool::directory::open(*this, path, imgenum); - if (err) - goto done; - - do - { - err = imgenum->get_next(ent); - if (err) - goto done; - - if (ent.eof) - { - err = (imgtoolerr_t)IMGTOOLERR_FILENOTFOUND; - goto done; - } - } - while(index--); - -done: - if (err) - memset(ent.filename, 0, sizeof(ent.filename)); - return err; -} - - -//------------------------------------------------- -// partition::get_file_size - returns free -// space on a partition, in bytes -//------------------------------------------------- - -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)); - - err = imgtool::directory::open(*this, path, imgenum); - if (err) - goto done; - - do - { - err = imgenum->get_next(ent); - if (err) - goto done; - - if (!core_stricmp(fname, ent.filename)) - { - filesize = ent.filesize; - goto done; - } - } - while(ent.filename[0]); - - err = (imgtoolerr_t)IMGTOOLERR_FILENOTFOUND; - -done: - return err; -} - - -//------------------------------------------------- -// partition::list_file_attributes - identifies -// all attributes on a file -//------------------------------------------------- - -imgtoolerr_t imgtool::partition::list_file_attributes(const char *path, uint32_t *attrs, size_t len) -{ - imgtoolerr_t err; - - memset(attrs, 0, sizeof(*attrs) * len); - - if (!m_list_attrs) - return imgtoolerr_t(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - // canonicalize path - std::string canonical_path; - err = canonicalize_path(PATH_LEAVENULLALONE, path, canonical_path); - if (err) - return err; - - err = m_list_attrs(*this, canonical_path.c_str(), attrs, len); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - -//------------------------------------------------- -// partition::get_file_attributes - retrieves -// attributes on a file -//------------------------------------------------- - -imgtoolerr_t imgtool::partition::get_file_attributes(const char *path, const uint32_t *attrs, imgtool_attribute *values) -{ - imgtoolerr_t err; - if (!m_get_attrs) - return imgtoolerr_t(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - // canonicalize path - std::string canonical_path; - err = canonicalize_path(PATH_LEAVENULLALONE, path, canonical_path); - if (err) - return err; - - err = m_get_attrs(*this, canonical_path.c_str(), attrs, values); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - -//------------------------------------------------- -// imgtool::partition::put_file_attributes - sets -// attributes on a file -//------------------------------------------------- - -imgtoolerr_t imgtool::partition::put_file_attributes(const char *path, const uint32_t *attrs, const imgtool_attribute *values) -{ - imgtoolerr_t err; - if (!m_set_attrs) - return imgtoolerr_t(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - // canonicalize path - std::string canonical_path; - err = canonicalize_path(PATH_LEAVENULLALONE, path, canonical_path); - if (err) - return err; - - err = m_set_attrs(*this, canonical_path.c_str(), attrs, values); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - -//------------------------------------------------- -// partition::get_file_attribute - retrieves -// an attribute on a single file -//------------------------------------------------- - -imgtoolerr_t imgtool::partition::get_file_attribute(const char *path, uint32_t attr, imgtool_attribute &value) -{ - uint32_t attrs[2]; - attrs[0] = attr; - attrs[1] = 0; - return get_file_attributes(path, attrs, &value); -} - - -//------------------------------------------------- -// partition::put_file_attribute - sets -// attributes on a single file -//------------------------------------------------- - -imgtoolerr_t imgtool::partition::put_file_attribute(const char *path, uint32_t attr, const imgtool_attribute &value) -{ - uint32_t attrs[2]; - attrs[0] = attr; - attrs[1] = 0; - return put_file_attributes(path, attrs, &value); -} - - -//------------------------------------------------- -// partition::get_icon_info - retrieves the -// icon for a file stored on a partition -//------------------------------------------------- - -imgtoolerr_t imgtool::partition::get_icon_info(const char *path, imgtool_iconinfo *iconinfo) -{ - imgtoolerr_t err; - if (!m_get_iconinfo) - return imgtoolerr_t(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - // canonicalize path - std::string canonical_path; - err = canonicalize_path(0, path, canonical_path); - if (err) - return err; - - memset(iconinfo, 0, sizeof(*iconinfo)); - err = m_get_iconinfo(*this, canonical_path.c_str(), iconinfo); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - -//------------------------------------------------- -// partition::suggest_file_filters - suggests a -// list of filters appropriate for a file on a -// partition -//------------------------------------------------- - -imgtoolerr_t imgtool::partition::suggest_file_filters(const char *path, - 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; - - // clear out buffer - memset(suggestions, 0, sizeof(*suggestions) * suggestions_length); - - if (!m_suggest_transfer) - return imgtoolerr_t(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - // canonicalize path - std::string canonical_path; - err = canonicalize_path(PATH_LEAVENULLALONE, path, canonical_path); - if (err) - return err; - - // invoke the module's suggest call - err = m_suggest_transfer(*this, canonical_path.c_str(), suggestions, suggestions_length); - if (err) - return err; - - // 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; - 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); - if (check_stream) - { - position = stream->tell(); - err = check_stream(*stream, &suggestions[i].viability); - stream->seek(position, SEEK_SET); - if (err) - return err; - } - } - - /* the check_stream proc can remove the option by clearing out the viability */ - if (suggestions[i].viability) - { - /* we may have to move this suggestion, if one was removed */ - if (i != j) - memcpy(&suggestions[j], &suggestions[i], sizeof(*suggestions)); - - /* if the description is missing, fill it in */ - if (!suggestions[j].description) - { - if (suggestions[j].filter) - suggestions[j].description = filter_get_info_string(suggestions[i].filter, FILTINFO_STR_HUMANNAME); - else - suggestions[j].description = "Raw"; - } - - j++; - } - i++; - } - suggestions[j].viability = (imgtool_suggestion_viability_t)0; - - return IMGTOOLERR_SUCCESS; -} - - -//------------------------------------------------- -// partition::get_chain - retrieves the block -// 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) -{ - 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++) - { - chain[i].level = 0; - chain[i].block = ~0; - } - - return m_get_chain(*this, path, chain, chain_size - 1); -} - - -//------------------------------------------------- -// partition::get_chain_string - retrieves -// the block chain for a file or directory on a -// partition -//------------------------------------------------- - -imgtoolerr_t imgtool::partition::get_chain_string(const char *path, char *buffer, size_t buffer_len) -{ - imgtoolerr_t err; - imgtool_chainent chain[512]; - uint64_t last_block; - uint8_t cur_level = 0; - int len, i; - int comma_needed = false; - - // determine the last block identifier - chain[0].block = ~0; - last_block = chain[0].block; - - err = get_chain(path, chain, std::size(chain)); - if (err) - return err; - - len = snprintf(buffer, buffer_len, "["); - buffer += len; - buffer_len -= len; - - for (i = 0; chain[i].block != last_block; i++) - { - while(cur_level < chain[i].level) - { - len = snprintf(buffer, buffer_len, " ["); - buffer += len; - buffer_len -= len; - cur_level++; - comma_needed = false; - } - while(cur_level > chain[i].level) - { - len = snprintf(buffer, buffer_len, "]"); - buffer += len; - buffer_len -= len; - cur_level--; - } - - if (comma_needed) - { - len = snprintf(buffer, buffer_len, ", "); - buffer += len; - buffer_len -= len; - } - - len = snprintf(buffer, buffer_len, "%u", (unsigned) chain[i].block); - buffer += len; - buffer_len -= len; - comma_needed = true; - } - - do - { - len = snprintf(buffer, buffer_len, "]"); - buffer += len; - buffer_len -= len; - } - while(cur_level-- > 0); - - return IMGTOOLERR_SUCCESS; -} - - -//------------------------------------------------- -// partition::get_free_space - returns the -// amount of free space on a partition -//------------------------------------------------- - -imgtoolerr_t imgtool::partition::get_free_space(uint64_t &sz) -{ - imgtoolerr_t err; - - if (!m_free_space) - return imgtoolerr_t(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - err = m_free_space(*this, &sz); - if (err) - return (imgtoolerr_t)(err | IMGTOOLERR_SRC_IMAGEFILE); - - return IMGTOOLERR_SUCCESS; -} - - -//------------------------------------------------- -// partition::read_file - starts reading -// from a file on a partition with a stream -//------------------------------------------------- - -imgtoolerr_t imgtool::partition::read_file(const char *filename, const char *fork, imgtool::stream &destf, filter_getinfoproc filter) -{ - imgtoolerr_t err; - union filterinfo u; - - if (!m_read_file) - return imgtoolerr_t(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - if (filter) - { - // use a filter - filter(FILTINFO_PTR_READFILE, &u); - if (!u.read_file) - return imgtoolerr_t(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - err = u.read_file(*this, filename, fork, destf); - if (err) - return markerrorsource(err); - } - else - { - // canonicalize path - std::string canonical_path; - err = canonicalize_path(PATH_CANBEBOOTBLOCK, filename, canonical_path); - if (err) - return err; - - err = canonicalize_fork(&fork); - if (err) - return err; - - // invoke the actual module - err = m_read_file(*this, canonical_path.c_str(), fork, destf); - if (err) - return markerrorsource(err); - } - - return IMGTOOLERR_SUCCESS; -} - - -//------------------------------------------------- -// partition::write_file - starts writing -// to a new file on an image with a stream -//------------------------------------------------- - -imgtoolerr_t imgtool::partition::write_file(const char *filename, const char *fork, imgtool::stream &sourcef, util::option_resolution *opts, filter_getinfoproc filter) -{ - imgtoolerr_t err; - std::unique_ptr alloc_resolution; - uint64_t free_space; - uint64_t file_size; - union filterinfo u; - - if (!m_write_file) - return imgtoolerr_t(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - if (filter) - { - // use a filter - filter(FILTINFO_PTR_WRITEFILE, &u); - if (!u.write_file) - return imgtoolerr_t(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - err = u.write_file(*this, filename, fork, sourcef, opts); - if (err) - return markerrorsource(err); - } - else - { - // does this partition prefer upper case file names? - std::string ucase_str; - if (m_prefer_ucase) - { - std::ostringstream s; - size_t i = 0; - while (filename[i]) - { - char32_t ch; - int count = uchar_from_utf8(&ch, &filename[i], UTF8_CHAR_MAX); - if (count > 0) - { - char32_t upper_ch = uchar_toupper(ch); - s << utf8_from_uchar(upper_ch); - } - i += count > 0 ? count : 1; - } - ucase_str = s.str(); - filename = ucase_str.c_str(); - } - - // canonicalize path - std::string canonical_path; - err = canonicalize_path(PATH_CANBEBOOTBLOCK, filename, canonical_path); - if (err) - return err; - - err = canonicalize_fork(&fork); - if (err) - return err; - - // allocate dummy options if necessary - if (!opts && m_writefile_optguide) - { - try { alloc_resolution.reset(new util::option_resolution(*m_writefile_optguide)); } - catch (...) - { - return IMGTOOLERR_OUTOFMEMORY; - } - if (!m_writefile_optspec.empty()) - alloc_resolution->set_specification(m_writefile_optspec); - opts = alloc_resolution.get(); - } - - // if free_space is implemented; do a quick check to see if space is available - if (m_free_space) - { - err = m_free_space(*this, &free_space); - if (err) - return markerrorsource(err); - - file_size = sourcef.size(); - - if (file_size > free_space) - return markerrorsource(IMGTOOLERR_NOSPACE); - } - - // actually invoke the write file handler - err = m_write_file(*this, canonical_path.c_str(), fork, sourcef, opts); - if (err) - return markerrorsource(err); - } - - return IMGTOOLERR_SUCCESS; -} - - -//------------------------------------------------- -// partition::get_file - read a file from -// an image, storing it into a native file -//------------------------------------------------- - -imgtoolerr_t imgtool::partition::get_file(const char *filename, const char *fork, - const char *dest, filter_getinfoproc filter) -{ - imgtoolerr_t err; - imgtool::stream::ptr f; - char *alloc_dest = nullptr; - const char *filter_extension = nullptr; - - if (!dest) - { - // determine the filter extension, if appropriate - if (filter != nullptr) - filter_extension = filter_get_info_string(filter, FILTINFO_STR_EXTENSION); - - if (filter_extension != nullptr) - { - alloc_dest = (char*)malloc(strlen(filename) + 1 + strlen(filter_extension) + 1); - if (!alloc_dest) - return IMGTOOLERR_OUTOFMEMORY; - - sprintf(alloc_dest, "%s.%s", filename, filter_extension); - dest = alloc_dest; - } - else - { - if (filename == FILENAME_BOOTBLOCK) - dest = "boot.bin"; - else - dest = filename; - } - } - - f = imgtool::stream::open(dest, OSD_FOPEN_WRITE); - if (!f) - { - err = imgtoolerr_t(IMGTOOLERR_FILENOTFOUND | IMGTOOLERR_SRC_NATIVEFILE); - goto done; - } - - err = read_file(filename, fork, *f, filter); - -done: - if (alloc_dest != nullptr) - free(alloc_dest); - return err; -} - - -//------------------------------------------------- -// partition::put_file - read a native file -// and store it on a partition -//------------------------------------------------- - -imgtoolerr_t imgtool::partition::put_file(const char *newfname, const char *fork, - const char *source, util::option_resolution *opts, filter_getinfoproc filter) -{ - imgtoolerr_t err; - imgtool::stream::ptr f; - std::string alloc_newfname; - std::string basename; - - if (!newfname) - { - basename = std::string(core_filename_extract_base(source)); - newfname = basename.c_str(); - } - - imgtool::charconverter *charconverter = (imgtool::charconverter *) get_info_ptr(IMGTOOLINFO_PTR_CHARCONVERTER); - if (charconverter) - { - // convert to native format - try - { - alloc_newfname = charconverter->from_utf8(newfname); - } - catch (charconverter_exception) - { - return imgtoolerr_t(IMGTOOLERR_BADFILENAME | IMGTOOLERR_SRC_NATIVEFILE); - } - newfname = alloc_newfname.c_str(); - } - - f = imgtool::stream::open(source, OSD_FOPEN_READ); - if (f) - err = write_file(newfname, fork, *f, opts, filter); - else - err = imgtoolerr_t(IMGTOOLERR_FILENOTFOUND | IMGTOOLERR_SRC_NATIVEFILE); - - return err; -} - - - -/*------------------------------------------------- - imgtool::partition::delete_file - delete a file - on a partition --------------------------------------------------*/ - -imgtoolerr_t imgtool::partition::delete_file(const char *fname) -{ - imgtoolerr_t err; - if (!m_delete_file) - return imgtoolerr_t(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - // canonicalize path - std::string canonical_path; - err = canonicalize_path(0, fname, canonical_path); - if (err) - return err; - - err = m_delete_file(*this, canonical_path.c_str()); - if (err) - return markerrorsource(err); - - return IMGTOOLERR_SUCCESS; -} - - -//------------------------------------------------- -// partition::list_file_forks - lists all -// forks on an image -//------------------------------------------------- - -imgtoolerr_t imgtool::partition::list_file_forks(const char *path, std::vector &forks) -{ - imgtoolerr_t err; - if (!m_list_forks) - return imgtoolerr_t(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - // canonicalize path - std::string canonical_path; - err = canonicalize_path(0, path, canonical_path); - if (err) - return err; - - // call the callback - forks.clear(); - err = m_list_forks(*this, canonical_path.c_str(), forks); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - -//------------------------------------------------- -// partition::create_directory - creates a -// directory on a partition -//------------------------------------------------- - -imgtoolerr_t imgtool::partition::create_directory(const char *path) -{ - imgtoolerr_t err; - - // implemented? - if (!m_create_dir) - return imgtoolerr_t(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - // canonicalize path - std::string canonical_path; - err = canonicalize_path(PATH_MUSTBEDIR, path, canonical_path); - if (err) - return err; - - err = m_create_dir(*this, path); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - -//------------------------------------------------- -// partition::delete_directory - deletes a -// directory on a partition -//------------------------------------------------- - -imgtoolerr_t imgtool::partition::delete_directory(const char *path) -{ - imgtoolerr_t err; - - // implemented? - if (!m_delete_dir) - return imgtoolerr_t(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - // canonicalize path - std::string canonical_path; - err = canonicalize_path(PATH_MUSTBEDIR, path, canonical_path); - if (err) - return err; - - err = m_delete_dir(*this, path); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - -//------------------------------------------------- -// partition::get_block_size - gets the -// size of a standard block on a partition -//------------------------------------------------- - -imgtoolerr_t imgtool::partition::get_block_size(uint32_t &length) -{ - return m_image.get_block_size(length); -} - - -//------------------------------------------------- -// partition::is_block_in_range -//------------------------------------------------- - -imgtoolerr_t imgtool::partition::map_block_to_image_block(uint64_t partition_block, uint64_t &image_block) const -{ - if (partition_block >= m_block_count) - return IMGTOOLERR_SEEKERROR; - - image_block = m_base_block + partition_block; - return IMGTOOLERR_SUCCESS; -} - - -//------------------------------------------------- -// partition::read_block - reads a standard -// block on a partition -//------------------------------------------------- - -imgtoolerr_t imgtool::partition::read_block(uint64_t block, void *buffer) -{ - uint64_t image_block; - imgtoolerr_t err = map_block_to_image_block(block, image_block); - if (err) - return err; - - return m_image.read_block(image_block, buffer); -} - - -//------------------------------------------------- -// partition::write_block - writes a -// standard block on a partition -//------------------------------------------------- - -imgtoolerr_t imgtool::partition::write_block(uint64_t block, const void *buffer) -{ - uint64_t image_block; - imgtoolerr_t err = map_block_to_image_block(block, image_block); - if (err) - return err; - - return m_image.write_block(image_block, buffer); -} - - -//------------------------------------------------- -// partition::get_features - retrieves a -// structure identifying this partition's features -// associated with an image -//------------------------------------------------- - -imgtool_partition_features imgtool::partition::get_features() const -{ - imgtool_partition_features features; - memset(&features, 0, sizeof(features)); - - if (m_read_file) - features.supports_reading = 1; - if (m_write_file) - features.supports_writing = 1; - if (m_delete_file) - features.supports_deletefile = 1; - if (m_path_separator) - features.supports_directories = 1; - if (m_free_space) - features.supports_freespace = 1; - if (m_create_dir) - features.supports_createdir = 1; - if (m_delete_dir) - features.supports_deletedir = 1; - if (m_supports_creation_time) - features.supports_creation_time = 1; - if (m_supports_lastmodified_time) - features.supports_lastmodified_time = 1; - if (m_get_iconinfo) - features.supports_geticoninfo = 1; - if (!features.supports_writing && !features.supports_createdir && !features.supports_deletefile && !features.supports_deletedir) - features.is_read_only = 1; - return features; -} - - -//------------------------------------------------- -// partition::get_info_ptr - retrieves a -// pointer associated with a partition's format -//------------------------------------------------- - -void *imgtool::partition::get_info_ptr(uint32_t state) -{ - return imgtool_get_info_ptr(&m_imgclass, state); -} - - -//------------------------------------------------- -// partition::get_info_string - retrieves a -// string associated with a partition's format -//------------------------------------------------- - -const char *imgtool::partition::get_info_string(uint32_t state) -{ - return imgtool_get_info_string(&m_imgclass, state); -} - - -//------------------------------------------------- -// partition::get_info_int - retrieves a -// pointer associated with a partition's format -//------------------------------------------------- - -uint64_t imgtool::partition::get_info_int(uint32_t state) -{ - return imgtool_get_info_int(&m_imgclass, state); -} - - -//------------------------------------------------- -// partition::extra_bytes - returns extra -// bytes on a partition -//------------------------------------------------- - -void *imgtool::partition::extra_bytes() -{ - if (!m_extra_bytes) - throw false; - return m_extra_bytes.get(); -} - - -/*************************************************************************** - - Path handling functions - -***************************************************************************/ - -//------------------------------------------------- -// partition::get_root_path - retrieves -// the path root of this partition -//------------------------------------------------- - -const char *imgtool::partition::get_root_path() -{ - int initial_path_separator; - char path_separator; - char *buf; - int pos = 0; - - initial_path_separator = get_info_int(IMGTOOLINFO_INT_INITIAL_PATH_SEPARATOR) ? 1 : 0; - path_separator = (char) get_info_int(IMGTOOLINFO_INT_PATH_SEPARATOR); - buf = imgtool_temp_str(); - - if (initial_path_separator) - buf[pos++] = path_separator; - buf[pos] = '\0'; - return buf; -} - - -//------------------------------------------------- -// partition::path_concatenate - retrieves -// a pointer associated with a partition's format -//------------------------------------------------- - -const char *imgtool::partition::path_concatenate(const char *path1, const char *path2) -{ - char path_separator; - size_t len; - char *buffer; - size_t buffer_len; - - path_separator = (char) get_info_int(IMGTOOLINFO_INT_PATH_SEPARATOR); - len = strlen(path1); - - /* prepare buffer */ - buffer = imgtool_temp_str(); - buffer_len = 256; - - if (!strcmp(path2, ".")) - { - /* keep the same directory */ - snprintf(buffer, buffer_len, "%s", path1); - } - else if (!strcmp(path2, "..")) - { - /* up one directory */ - while((len > 0) && (path1[len - 1] == path_separator)) - len--; - while((len > 0) && (path1[len - 1] != path_separator)) - len--; - while((len > 1) && (path1[len - 1] == path_separator)) - len--; - snprintf(buffer, buffer_len, "%s", path1); - buffer[len] = '\0'; - } - else - { - /* append a path */ - if ((*path1 != 0) && (path1[strlen(path1) - 1] != path_separator)) - snprintf(buffer, buffer_len, "%s%c%s", path1, path_separator, path2); - else - snprintf(buffer, buffer_len, "%s%s", path1, path2); - } - return buffer; -} - - -//------------------------------------------------- -// partition::get_base_name - retrieves -// a base name for a partition specific path -//------------------------------------------------- - -const char *imgtool::partition::get_base_name(const char *path) -{ - char path_separator; - const char *new_path = path; - int i; - - path_separator = (char) get_info_int(IMGTOOLINFO_INT_PATH_SEPARATOR); - - for (i = 0; path[i]; i++) - { - if (path[i] == path_separator) - new_path = &path[i + 1]; - } - return new_path; -} - - - -/*************************************************************************** - - Directory handling functions - -***************************************************************************/ - -//------------------------------------------------- -// directory ctor -//------------------------------------------------- - -imgtool::directory::directory(imgtool::partition &partition) - : m_partition(partition) - , m_okay_to_close(false) -{ - if (partition.m_directory_extra_bytes > 0) - { - m_extra_bytes = std::make_unique(partition.m_directory_extra_bytes); - memset(m_extra_bytes.get(), 0, sizeof(m_extra_bytes.get()[0] * partition.m_directory_extra_bytes)); - } -} - - -//------------------------------------------------- -// directory::open - begins -// enumerating files on a partition -//------------------------------------------------- - -imgtoolerr_t imgtool::directory::open(imgtool::partition &partition, const std::string &path, imgtool::directory::ptr &outenum) -{ - imgtoolerr_t err = imgtoolerr_t(IMGTOOLERR_SUCCESS); - imgtool::directory::ptr enumeration; - - outenum.reset(); - - if (!partition.m_next_enum) - return imgtoolerr_t(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - std::string canonical_path; - err = partition.canonicalize_path(PATH_MUSTBEDIR, path.c_str(), canonical_path); - if (err) - return err; - - try { enumeration = std::make_unique(partition); } - catch (std::bad_alloc const &) - { - return imgtoolerr_t(IMGTOOLERR_OUTOFMEMORY); - } - - if (partition.m_begin_enum) - { - err = partition.m_begin_enum(*enumeration, canonical_path.c_str()); - if (err) - return markerrorsource(err); - } - - enumeration->m_okay_to_close = true; - outenum = std::move(enumeration); - - return IMGTOOLERR_SUCCESS; -} - - -//------------------------------------------------- -// directory dtor -//------------------------------------------------- - -imgtool::directory::~directory() -{ - if (m_okay_to_close && m_partition.m_close_enum) - m_partition.m_close_enum(*this); -} - - -//------------------------------------------------- -// directory::get_next - continues -// enumerating files within a partition -//------------------------------------------------- - -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)); - - err = m_partition.m_next_enum(*this, ent); - if (err) - return markerrorsource(err); - - imgtool::charconverter * const converter = reinterpret_cast(m_partition.get_info_ptr(IMGTOOLINFO_PTR_CHARCONVERTER)); - if (converter) - { - std::string new_fname; - try - { - new_fname = converter->to_utf8(ent.filename); - } - catch (charconverter_exception) - { - return imgtoolerr_t(IMGTOOLERR_BADFILENAME); - } - snprintf(ent.filename, std::size(ent.filename), "%s", new_fname.c_str()); - } - - // don't trust the module! - if (!m_partition.m_supports_creation_time && (ent.creation_time.type() != imgtool::datetime::datetime_type::NONE)) - { - internal_error(nullptr, "next_enum() specified creation_time, which is marked as unsupported by this module"); - return IMGTOOLERR_UNEXPECTED; - } - if (!m_partition.m_supports_lastmodified_time && (ent.lastmodified_time.type() != imgtool::datetime::datetime_type::NONE)) - { - internal_error(nullptr, "next_enum() specified lastmodified_time, which is marked as unsupported by this module"); - return IMGTOOLERR_UNEXPECTED; - } - if (!m_partition.m_path_separator && ent.directory) - { - internal_error(nullptr, "next_enum() returned a directory, which is marked as unsupported by this module"); - return IMGTOOLERR_UNEXPECTED; - } - return IMGTOOLERR_SUCCESS; -} - - -//------------------------------------------------- -// unknown_partition_get_info - represents an -// unknown partition -//------------------------------------------------- - -void unknown_partition_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(), "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 deleted file mode 100644 index 4a66d7f..0000000 --- a/src/tools/imgtool/imgtool.h +++ /dev/null @@ -1,265 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/*************************************************************************** - - imgtool.h - - Main headers for Imgtool core - -***************************************************************************/ - -#ifndef IMGTOOL_H -#define IMGTOOL_H - -#include "library.h" -#include "stream.h" - -#include "osdcomm.h" - -#include -#include -#include - -/* ----------------------------------------------------------------------- */ - -#define EOLN_CR "\x0d" -#define EOLN_LF "\x0a" -#define EOLN_CRLF "\x0d\x0a" - -#define FILENAME_BOOTBLOCK ((const char *) 1) - -enum -{ - OSD_FOPEN_READ, - OSD_FOPEN_WRITE, - OSD_FOPEN_RW, - OSD_FOPEN_RW_CREATE -}; - -/* --------------------------------------------------------------------------- - * Image calls - * - * These are the calls that front ends should use for manipulating images. You - * should never call the module functions directly because they may not be - * implemented (i.e. - the function pointers are NULL). The img_* functions are - * aware of these issues and will make the appropriate checks as well as - * marking up return codes with the source. In addition, some of the img_* - * calls are high level calls that simply image manipulation - * - * Calls that return 'int' that are not explicitly noted otherwise return - * imgtool error codes - * --------------------------------------------------------------------------- - */ - -struct imgtool_module_features -{ - unsigned int supports_create : 1; - unsigned int supports_open : 1; - unsigned int supports_readsector : 1; - unsigned int supports_writesector : 1; - unsigned int is_read_only : 1; -}; - -struct imgtool_partition_features -{ - unsigned int supports_reading : 1; - unsigned int supports_writing : 1; - unsigned int supports_deletefile : 1; - unsigned int supports_directories : 1; - unsigned int supports_freespace : 1; - unsigned int supports_createdir : 1; - unsigned int supports_deletedir : 1; - unsigned int supports_creation_time : 1; - unsigned int supports_lastmodified_time : 1; - unsigned int supports_forks : 1; - unsigned int supports_geticoninfo : 1; - unsigned int is_read_only : 1; -}; - -/* ----- initialization and basics ----- */ -void imgtool_init(bool omit_untested, void (*warning)(const char *message)); -void imgtool_exit(void); -const imgtool_module *imgtool_find_module(const std::string &modulename); -const imgtool::library::modulelist &imgtool_get_modules(); -imgtool_module_features imgtool_get_module_features(const imgtool_module *module); -void imgtool_warn(const char *format, ...) ATTR_PRINTF(1,2); - -// ----- image management ----- -namespace imgtool -{ - class image - { - public: - typedef std::unique_ptr ptr; - - image(const imgtool_module &module); - ~image(); - - static imgtoolerr_t identify_file(const char *filename, imgtool_module **modules, size_t count); - static imgtoolerr_t open(const imgtool_module *module, const std::string &filename, int read_or_write, ptr &outimg); - static imgtoolerr_t open(const std::string &modulename, const std::string &filename, int read_or_write, ptr &outimg); - static imgtoolerr_t create(const imgtool_module *module, const std::string &filename, util::option_resolution *opts, ptr &image); - static imgtoolerr_t create(const std::string &modulename, const std::string &filename, util::option_resolution *opts, ptr &image); - static imgtoolerr_t create(const imgtool_module *module, const std::string &filename, util::option_resolution *opts); - static imgtoolerr_t create(const std::string &modulename, const std::string &filename, util::option_resolution *opts); - - std::string info(); - imgtoolerr_t get_geometry(uint32_t *tracks, uint32_t *heads, uint32_t *sectors); - imgtoolerr_t read_sector(uint32_t track, uint32_t head, uint32_t sector, std::vector &buffer); - imgtoolerr_t write_sector(uint32_t track, uint32_t head, uint32_t sector, const void *buffer, size_t len); - 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 clear_block(uint64_t block, uint8_t data); - imgtoolerr_t list_partitions(std::vector &partitions); - const imgtool_module &module() { return m_module; } - void *extra_bytes() { return m_extra_bytes.get(); } - - private: - const imgtool_module &m_module; - std::unique_ptr 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 - // better C++ adoption (e.g. - std::unique_ptr<>, std:move() etc) - bool m_okay_to_close; - - static imgtoolerr_t internal_open(const imgtool_module *module, const std::string &filename, - int read_or_write, util::option_resolution *createopts, imgtool::image::ptr &outimg); - }; -} - -namespace imgtool -{ - // ----- partition management ----- - class partition - { - friend class directory; - public: - typedef std::unique_ptr ptr; - - // ctor/dtor - partition(imgtool::image &image, const imgtool_class &imgclass, int partition_index, uint64_t base_block, uint64_t block_count); - ~partition(); - - static imgtoolerr_t open(imgtool::image &image, int partition_index, ptr &partition); - imgtool::image &image() { return m_image; } - - // ----- partition operations ----- - imgtoolerr_t get_directory_entry(const char *path, int index, imgtool_dirent &ent); - imgtoolerr_t get_file_size(const char *filename, uint64_t &filesize); - imgtoolerr_t get_free_space(uint64_t &sz); - imgtoolerr_t read_file(const char *filename, const char *fork, imgtool::stream &destf, filter_getinfoproc filter); - imgtoolerr_t write_file(const char *filename, const char *fork, imgtool::stream &sourcef, util::option_resolution *resolution, filter_getinfoproc filter); - imgtoolerr_t get_file(const char *filename, const char *fork, const char *dest, filter_getinfoproc filter); - imgtoolerr_t put_file(const char *newfname, const char *fork, const char *source, util::option_resolution *opts, filter_getinfoproc filter); - imgtoolerr_t delete_file(const char *fname); - imgtoolerr_t list_file_forks(const char *path, std::vector &forks); - imgtoolerr_t create_directory(const char *path); - imgtoolerr_t delete_directory(const char *path); - imgtoolerr_t list_file_attributes(const char *path, uint32_t *attrs, size_t len); - imgtoolerr_t get_file_attributes(const char *path, const uint32_t *attrs, imgtool_attribute *values); - imgtoolerr_t put_file_attributes(const char *path, const uint32_t *attrs, const imgtool_attribute *values); - imgtoolerr_t get_file_attribute(const char *path, uint32_t attr, imgtool_attribute &value); - 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 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_string(const char *path, char *buffer, size_t buffer_len); - imgtool_partition_features get_features() const; - void * get_info_ptr(uint32_t state); - const char * get_info_string(uint32_t state); - uint64_t get_info_int(uint32_t state); - void * extra_bytes(); - - // ----- path management ----- - const char * get_root_path(); - const char * path_concatenate(const char *path1, const char *path2); - const char * get_base_name(const char *path); - - private: - imgtool::image &m_image; - //int m_partition_index; - uint64_t m_base_block; - uint64_t m_block_count; - - imgtool_class m_imgclass; - size_t m_directory_extra_bytes; - - char m_path_separator; - char m_alternate_path_separator; - - unsigned int m_prefer_ucase : 1; - unsigned int m_supports_creation_time : 1; - unsigned int m_supports_lastmodified_time : 1; - unsigned int m_supports_bootblock : 1; /* this module supports loading/storing the boot block */ - - std::function m_begin_enum; - std::function m_next_enum; - std::function m_close_enum; - std::function m_free_space; - std::function m_read_file; - std::function m_write_file; - std::function m_delete_file; - std::function &forks)> m_list_forks; - std::function m_create_dir; - std::function m_delete_dir; - std::function m_list_attrs; - std::function m_get_attrs; - std::function m_set_attrs; - std::function m_attr_name; - std::function m_get_iconinfo; - std::function m_suggest_transfer; - std::function m_get_chain; - - const util::option_guide *m_writefile_optguide; - std::string m_writefile_optspec; - - std::unique_ptr m_extra_bytes; - - // methods - imgtoolerr_t canonicalize_path(uint32_t flags, const char *path, std::string &result); - imgtoolerr_t canonicalize_fork(const char **fork); - imgtoolerr_t map_block_to_image_block(uint64_t partition_block, uint64_t &image_block) const; - }; - - // ----- directory management ----- - class directory - { - public: - typedef std::unique_ptr ptr; - - // ctor/dtor - directory(imgtool::partition &partition); - ~directory(); - - // methods - static imgtoolerr_t open(imgtool::partition &partition, const std::string &path, ptr &outenum); - imgtoolerr_t get_next(imgtool_dirent &ent); - - // accessors - imgtool::partition &partition() { return m_partition; } - imgtool::image &image() { return partition().image(); } - const imgtool_module &module() { return partition().image().module(); } - void *extra_bytes() { assert(m_extra_bytes); return m_extra_bytes.get(); } - - private: - imgtool::partition &m_partition; - std::unique_ptr m_extra_bytes; - bool m_okay_to_close; // similar wart as what is on imgtool::image - }; -}; - -/* ----- special ----- */ -bool imgtool_validitychecks(void); -void unknown_partition_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info); - -char *strncpyz(char *dest, const char *source, size_t len); -void rtrim(char *buf); -std::string extract_padded_filename(const char *source, size_t filename_length, size_t extension_length, char pad = ' '); - -#endif /* IMGTOOL_H */ diff --git a/src/tools/imgtool/library.cpp b/src/tools/imgtool/library.cpp deleted file mode 100644 index f53db6f..0000000 --- a/src/tools/imgtool/library.cpp +++ /dev/null @@ -1,314 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/**************************************************************************** - - library.cpp - - Code relevant to the Imgtool library; analogous to the MESS/MAME driver - list. - -****************************************************************************/ - -#include "library.h" - -#include "corestr.h" - -#include -#include - -namespace imgtool { - -datetime::imgtool_clock::duration datetime::s_gmt_offset = datetime::calculate_gmt_offset(); - -//------------------------------------------------- -// datetime ctor -//------------------------------------------------- - -datetime::datetime(datetime_type type, std::chrono::time_point tp) - : m_type(type) - , m_time_point(imgtool_clock::from_system_clock(tp)) -{ -} - - -//------------------------------------------------- -// datetime ctor -//------------------------------------------------- - -datetime::datetime(datetime_type type, time_t t) - : datetime(type, std::chrono::system_clock::from_time_t(t)) -{ -} - - -//------------------------------------------------- -// datetime ctor -//------------------------------------------------- - -datetime::datetime(datetime_type type, const util::arbitrary_datetime &dt, bool clamp) - : m_type(type) - , m_time_point(imgtool_clock::from_arbitrary_datetime(dt, clamp)) -{ -} - - -//------------------------------------------------- -// datetime::now -//------------------------------------------------- - -datetime datetime::now(datetime_type type) -{ - return imgtool::datetime( - type, - std::chrono::system_clock::now()); -} - - -//------------------------------------------------- -// datetime::localtime -//------------------------------------------------- - -std::tm datetime::localtime() const -{ - imgtool_clock::time_point tp; - - switch (type()) - { - case datetime_type::LOCAL: - tp = time_point(); - break; - case datetime_type::GMT: - tp = time_point() + s_gmt_offset; - break; - default: - tp = imgtool_clock::time_point(); - break; - } - return imgtool_clock::to_tm(tp); -} - - -//------------------------------------------------- -// datetime::gmtime -//------------------------------------------------- - -std::tm datetime::gmtime() const -{ - imgtool_clock::time_point tp; - - switch (type()) - { - case datetime_type::GMT: - tp = time_point(); - break; - case datetime_type::LOCAL: - tp = time_point() - s_gmt_offset; - break; - default: - tp = imgtool_clock::time_point(); - break; - } - return imgtool_clock::to_tm(tp); -} - - -//------------------------------------------------- -// datetime::calculate_gmt_offset -//------------------------------------------------- - -datetime::imgtool_clock::duration datetime::calculate_gmt_offset() -{ - time_t t = time(nullptr); - std::tm utc_tm = *std::gmtime(&t); - time_t utc = mktime(&utc_tm); - std::tm local_tm = *std::localtime(&t); - time_t local = mktime(&local_tm); - double d = difftime(local, utc) * imgtool_clock::period::den / imgtool_clock::period::num; - return imgtool_clock::duration((std::int64_t) d); -} - - -//------------------------------------------------- -// datetime::to_time_t -//------------------------------------------------- - -time_t datetime::to_time_t() const -{ - auto system_clock_tp = imgtool_clock::to_system_clock(time_point()); - return std::chrono::system_clock::to_time_t(system_clock_tp); -} - - -//------------------------------------------------- -// ctor -//------------------------------------------------- - -library::library() -{ -} - - -//------------------------------------------------- -// dtor -//------------------------------------------------- - -library::~library() -{ -} - - -//------------------------------------------------- -// add_class -//------------------------------------------------- - -void library::add_class(const imgtool_class *imgclass) -{ - char const *temp; - - // allocate the module and place it in the chain - m_modules.emplace_back(std::make_unique()); - imgtool_module *module = m_modules.back().get(); - - module->imgclass = *imgclass; - 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_get_info_fct(imgclass, IMGTOOLINFO_PTR_OPEN); - module->create = (imgtoolerr_t (*)(imgtool::image &, std::unique_ptr &&, 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 &)) imgtool_get_info_fct(imgclass, IMGTOOLINFO_PTR_READ_SECTOR); - module->write_sector = (imgtoolerr_t (*)(imgtool::image &, uint32_t, uint32_t, uint32_t, const void *, size_t)) imgtool_get_info_fct(imgclass, IMGTOOLINFO_PTR_WRITE_SECTOR); - module->get_geometry = (imgtoolerr_t (*)(imgtool::image &, uint32_t *, uint32_t *, uint32_t *))imgtool_get_info_fct(imgclass, IMGTOOLINFO_PTR_GET_GEOMETRY); - module->read_block = (imgtoolerr_t (*)(imgtool::image &, void *, uint64_t)) imgtool_get_info_fct(imgclass, IMGTOOLINFO_PTR_READ_BLOCK); - module->write_block = (imgtoolerr_t (*)(imgtool::image &, const void *, uint64_t)) imgtool_get_info_fct(imgclass, IMGTOOLINFO_PTR_WRITE_BLOCK); - module->list_partitions = (imgtoolerr_t (*)(imgtool::image &, std::vector &)) 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); - 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); -} - - -//------------------------------------------------- -// add -//------------------------------------------------- - -void library::add(imgtool_get_info get_info) -{ - int (*make_class)(int index, imgtool_class *imgclass); - imgtool_class imgclass; - int i, result; - - // try this class - memset(&imgclass, 0, sizeof(imgclass)); - imgclass.get_info = get_info; - - // do we have derived getinfo functions? - make_class = (int (*)(int index, imgtool_class *imgclass)) - imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_MAKE_CLASS); - - if (make_class) - { - i = 0; - do - { - // clear out the class - memset(&imgclass, 0, sizeof(imgclass)); - imgclass.get_info = get_info; - - // make the class - result = make_class(i++, &imgclass); - if (result) - add_class(&imgclass); - } - while(result); - } - else - { - add_class(&imgclass); - } -} - - -//------------------------------------------------- -// unlink -//------------------------------------------------- - -void library::unlink(const std::string &module_name) -{ - const modulelist::iterator iter = find(module_name); - if (iter != m_modules.end()) - m_modules.erase(iter); -} - - -//------------------------------------------------- -// module_compare -//------------------------------------------------- - -int library::module_compare(const imgtool_module *m1, const imgtool_module *m2, sort_type sort) -{ - int rc = 0; - switch(sort) - { - case sort_type::NAME: - rc = strcmp(m1->name.c_str(), m2->name.c_str()); - break; - case sort_type::DESCRIPTION: - rc = core_stricmp(m1->description.c_str(), m2->description.c_str()); - break; - } - return rc; -} - - -//------------------------------------------------- -// sort -//------------------------------------------------- - -void library::sort(sort_type sort) -{ - auto compare = [this, sort](const std::unique_ptr &a, const std::unique_ptr &b) - { - return module_compare(a.get(), b.get(), sort) < 0; - }; - m_modules.sort(compare); -} - - -//------------------------------------------------- -// find -//------------------------------------------------- - -library::modulelist::iterator library::find(const std::string &module_name) -{ - return std::find_if( - m_modules.begin(), - m_modules.end(), - [module_name](std::unique_ptr &module) { return !module_name.compare(module->name); }); -} - - -//------------------------------------------------- -// findmodule -//------------------------------------------------- - -const imgtool_module *library::findmodule(const std::string &module_name) -{ - modulelist::iterator iter = find(module_name); - return iter != m_modules.end() - ? iter->get() - : nullptr; -} - - -} // namespace imgtool diff --git a/src/tools/imgtool/library.h b/src/tools/imgtool/library.h deleted file mode 100644 index 312d3bb..0000000 --- a/src/tools/imgtool/library.h +++ /dev/null @@ -1,551 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/**************************************************************************** - - library.h - - Code relevant to the Imgtool library; analogous to the MAME driver list. - - 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 - -#pragma once - -#include "imgterrs.h" - -#include "timeconv.h" -#include "utilfwd.h" - -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace imgtool -{ - class image; - class partition; - class directory; - class charconverter; - class stream; -}; - -enum imgtool_suggestion_viability_t -{ - SUGGESTION_END, - SUGGESTION_POSSIBLE, - SUGGESTION_RECOMMENDED -}; - -union filterinfo -{ - int64_t i; /* generic integers */ - void * p; /* generic pointers */ - void * f; /* generic function pointers */ - const char *s; /* generic strings */ - - 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); -}; - -typedef void (*filter_getinfoproc)(uint32_t state, union filterinfo *info); - -namespace imgtool -{ - class datetime - { - public: - typedef util::arbitrary_clock > imgtool_clock; - - enum datetime_type - { - NONE, - LOCAL, - GMT - }; - - datetime() - : m_type(datetime_type::NONE) - { - } - - - template - datetime(datetime_type type, std::chrono::time_point > tp) - : m_type(type) - , m_time_point(imgtool_clock::from_arbitrary_time_point(tp)) - { - } - - datetime(datetime_type type, std::chrono::time_point 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 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; - } - - // 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; - - private: - static imgtool_clock::duration s_gmt_offset; - datetime_type m_type; - std::chrono::time_point m_time_point; - - 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 -{ - uint8_t level; - uint64_t block; -}; - -namespace imgtool -{ - class fork_entry - { - 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)) - { - - } - - 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; - - 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) - { - 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; - }; -} - -struct imgtool_transfer_suggestion -{ - imgtool_suggestion_viability_t viability; - filter_getinfoproc filter; - const char *fork; - const char *description; -}; - -enum -{ - /* --- the following bits of info are returned as 64-bit signed integers --- */ - IMGTOOLATTR_INT_FIRST = 0x00000, - 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_ICONID, - IMGTOOLATTR_INT_MAC_SCRIPTCODE, - IMGTOOLATTR_INT_MAC_EXTENDEDFLAGS, - IMGTOOLATTR_INT_MAC_COMMENTID, - IMGTOOLATTR_INT_MAC_PUTAWAYDIRECTORY, - - /* --- the following bits of info are returned as pointers to data or functions --- */ - IMGTOOLATTR_PTR_FIRST = 0x10000, - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - IMGTOOLATTR_STR_FIRST = 0x20000, - - /* --- the following bits of info are returned as time_t values --- */ - IMGTOOLATTR_TIME_FIRST = 0x30000, - IMGTOOLATTR_TIME_CREATED, - IMGTOOLATTR_TIME_LASTMODIFIED -}; - -union imgtool_attribute -{ - int64_t i; - time_t t; -}; - -struct imgtool_iconinfo -{ - unsigned icon16x16_specified : 1; - unsigned icon32x32_specified : 1; - uint32_t icon16x16[16][16]; - uint32_t icon32x32[32][32]; -}; - -enum -{ - /* --- the following bits of info are returned as 64-bit signed integers --- */ - IMGTOOLINFO_INT_FIRST = 0x00000, - IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES, - IMGTOOLINFO_INT_PARTITION_EXTRA_BYTES, - IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES, - IMGTOOLINFO_INT_PATH_SEPARATOR, - IMGTOOLINFO_INT_ALTERNATE_PATH_SEPARATOR, - IMGTOOLINFO_INT_PREFER_UCASE, - IMGTOOLINFO_INT_INITIAL_PATH_SEPARATOR, - IMGTOOLINFO_INT_OPEN_IS_STRICT, - IMGTOOLINFO_INT_SUPPORTS_CREATION_TIME, - IMGTOOLINFO_INT_SUPPORTS_LASTMODIFIED_TIME, - IMGTOOLINFO_INT_TRACKS_ARE_CALLED_CYLINDERS, - IMGTOOLINFO_INT_WRITING_UNTESTED, - IMGTOOLINFO_INT_CREATION_UNTESTED, - IMGTOOLINFO_INT_SUPPORTS_BOOTBLOCK, - IMGTOOLINFO_INT_BLOCK_SIZE, - - IMGTOOLINFO_INT_CLASS_SPECIFIC = 0x08000, - - /* --- the following bits of info are returned as pointers to data or functions --- */ - IMGTOOLINFO_PTR_FIRST = 0x10000, - - IMGTOOLINFO_PTR_OPEN, - IMGTOOLINFO_PTR_CREATE, - IMGTOOLINFO_PTR_CLOSE, - IMGTOOLINFO_PTR_OPEN_PARTITION, - IMGTOOLINFO_PTR_CREATE_PARTITION, - IMGTOOLINFO_PTR_INFO, - IMGTOOLINFO_PTR_BEGIN_ENUM, - IMGTOOLINFO_PTR_NEXT_ENUM, - IMGTOOLINFO_PTR_CLOSE_ENUM, - IMGTOOLINFO_PTR_FREE_SPACE, - IMGTOOLINFO_PTR_READ_FILE, - IMGTOOLINFO_PTR_WRITE_FILE, - IMGTOOLINFO_PTR_DELETE_FILE, - IMGTOOLINFO_PTR_LIST_FORKS, - IMGTOOLINFO_PTR_CREATE_DIR, - IMGTOOLINFO_PTR_DELETE_DIR, - IMGTOOLINFO_PTR_LIST_ATTRS, - IMGTOOLINFO_PTR_GET_ATTRS, - IMGTOOLINFO_PTR_SET_ATTRS, - IMGTOOLINFO_PTR_ATTR_NAME, - IMGTOOLINFO_PTR_GET_ICON_INFO, - IMGTOOLINFO_PTR_SUGGEST_TRANSFER, - IMGTOOLINFO_PTR_GET_CHAIN, - IMGTOOLINFO_PTR_GET_GEOMETRY, - IMGTOOLINFO_PTR_READ_SECTOR, - IMGTOOLINFO_PTR_WRITE_SECTOR, - IMGTOOLINFO_PTR_READ_BLOCK, - IMGTOOLINFO_PTR_WRITE_BLOCK, - IMGTOOLINFO_PTR_APPROVE_FILENAME_CHAR, - IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE, - IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE, - IMGTOOLINFO_PTR_MAKE_CLASS, - IMGTOOLINFO_PTR_LIST_PARTITIONS, - IMGTOOLINFO_PTR_CHARCONVERTER, - - IMGTOOLINFO_PTR_CLASS_SPECIFIC = 0x18000, - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - IMGTOOLINFO_STR_FIRST = 0x20000, - - IMGTOOLINFO_STR_NAME, - IMGTOOLINFO_STR_DESCRIPTION, - IMGTOOLINFO_STR_FILE, - IMGTOOLINFO_STR_FILE_EXTENSIONS, - IMGTOOLINFO_STR_EOLN, - IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC, - IMGTOOLINFO_STR_WRITEFILE_OPTSPEC, - - IMGTOOLINFO_STR_CLASS_SPECIFIC = 0x28000 -}; - - - -union imgtoolinfo; - -struct imgtool_class; -typedef void (*imgtool_get_info)(const imgtool_class *, uint32_t, union imgtoolinfo *); - -struct imgtool_class -{ - imgtool_get_info get_info; - imgtool_get_info derived_get_info; - void *derived_param; -}; - - - -namespace imgtool -{ - class partition_info - { - public: - partition_info(imgtool_get_info get_info, uint64_t base_block, uint64_t block_count) - : m_base_block(base_block) - , m_block_count(block_count) - { - memset(&m_imgclass, 0, sizeof(m_imgclass)); - m_imgclass.get_info = get_info; - } - - partition_info(imgtool_class imgclass, uint64_t base_block, uint64_t block_count) - : m_imgclass(imgclass) - , m_base_block(base_block) - , m_block_count(block_count) - { - } - - const imgtool_class &imgclass() const { return m_imgclass; } - uint64_t base_block() const { return m_base_block; } - uint64_t block_count() const { return m_block_count; } - - private: - imgtool_class m_imgclass; - uint64_t m_base_block; - uint64_t m_block_count; - }; -}; - - -union imgtoolinfo -{ - int64_t i; /* generic integers */ - void * p; /* generic pointers */ - void * f; /* generic function pointers */ - char * s; /* generic strings */ - - imgtoolerr_t (*open) (imgtool::image &image, std::unique_ptr &&stream); - void (*close) (imgtool::image &image); - imgtoolerr_t (*create) (imgtool::image &image, std::unique_ptr &&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); - imgtoolerr_t (*next_enum) (imgtool::directory &enumeration, imgtool_dirent &ent); - void (*close_enum) (imgtool::directory &enumeration); - imgtoolerr_t (*open_partition) (imgtool::partition &partition, uint64_t first_block, uint64_t block_count); - imgtoolerr_t (*free_space) (imgtool::partition &partition, uint64_t *size); - 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 (*delete_file) (imgtool::partition &partition, const char *filename); - imgtoolerr_t (*list_forks) (imgtool::partition &partition, const char *path, std::vector &forks); - imgtoolerr_t (*create_dir) (imgtool::partition &partition, const char *path); - imgtoolerr_t (*delete_dir) (imgtool::partition &partition, const char *path); - imgtoolerr_t (*list_attrs) (imgtool::partition &partition, const char *path, uint32_t *attrs, size_t len); - imgtoolerr_t (*get_attrs) (imgtool::partition &partition, const char *path, const uint32_t *attrs, imgtool_attribute *values); - 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 (*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 &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); - 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 &partitions); - int (*approve_filename_char)(char32_t ch); - int (*make_class)(int index, imgtool_class *imgclass); - - const util::option_guide *createimage_optguide; - const util::option_guide *writefile_optguide; - const imgtool::charconverter *charconverter; -}; - - - -static inline int64_t imgtool_get_info_int(const imgtool_class *imgclass, uint32_t state) -{ - union imgtoolinfo info; - info.i = 0; - imgclass->get_info(imgclass, state, &info); - return info.i; -} - -static inline void *imgtool_get_info_ptr(const imgtool_class *imgclass, uint32_t state) -{ - union imgtoolinfo info; - info.p = nullptr; - imgclass->get_info(imgclass, state, &info); - return info.p; -} - -static inline void *imgtool_get_info_fct(const imgtool_class *imgclass, uint32_t state) -{ - union imgtoolinfo info; - info.f = nullptr; - imgclass->get_info(imgclass, state, &info); - return info.f; -} - -static inline char *imgtool_get_info_string(const imgtool_class *imgclass, uint32_t state) -{ - union imgtoolinfo info; - info.s = nullptr; - imgclass->get_info(imgclass, state, &info); - return info.s; -} - -/* circular string buffer */ -char *imgtool_temp_str(void); - - - -struct imgtool_module -{ - imgtool_class imgclass = { 0 }; - - std::string name; - std::string description; - std::string extensions; - std::string eoln; - - size_t image_extra_bytes = 0; - - /* flags */ - 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 &&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 &&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 &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 &partitions) = nullptr; - - uint32_t block_size = 0; - - const util::option_guide *createimage_optguide = nullptr; - std::string createimage_optspec; - - const void *extra = nullptr; -}; - -namespace imgtool { - -//************************************************************************** -// TYPE DEFINITIONS -//************************************************************************** - -// imgtool "library" - equivalent to the MAME driver list -class library -{ -public: - typedef std::list > modulelist; - - enum class sort_type - { - NAME, - DESCRIPTION - }; - - library(); - ~library(); - - // adds a module to an imgtool library - void add(imgtool_get_info get_info); - - // seeks out and removes a module from an imgtool library - void unlink(const std::string &module_name); - - // sorts an imgtool library - void sort(sort_type sort); - - // finds a module - const imgtool_module *findmodule(const std::string &module_name); - - // module iteration - const modulelist &modules() { return m_modules; } - -private: - modulelist m_modules; - - // internal lookup and iteration - modulelist::iterator find(const std::string &module_name); - - // helpers - void add_class(const imgtool_class *imgclass); - int module_compare(const imgtool_module *m1, const imgtool_module *m2, sort_type sort); -}; - -} // namespace imgtool - -#endif // MAME_TOOLS_IMGTOOL_LIBRARY_H diff --git a/src/tools/imgtool/main.cpp b/src/tools/imgtool/main.cpp deleted file mode 100644 index d8a166e..0000000 --- a/src/tools/imgtool/main.cpp +++ /dev/null @@ -1,966 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/*************************************************************************** - - main.cpp - - Imgtool command line front end - -***************************************************************************/ - -#include "imgtool.h" -#include "filter.h" -#include "main.h" -#include "modules.h" - -#include "corefile.h" -#include "corestr.h" -#include "opresolv.h" -#include "strformat.h" -#include "unicode.h" - -#include "osdcore.h" // osd_get_command_line - -#include -#include -#include -#include -#include -#include - -#ifdef _WIN32 -#include -#include -#endif - -// ---------------------------------------------------------------------- - -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])); - - util::stream_format(output, - L"%s %s %s %s\n", - (write_word_usage ? L"Usage:" : L" "), - wstring_from_utf8(cmdname), - wstring_from_utf8(c->name), - c->usage ? wstring_from_utf8(c->usage) : std::wstring()); -} - - -// ---------------------------------------------------------------------- - -static int parse_options(int argc, char *argv[], int minunnamed, int maxunnamed, - util::option_resolution *resolution, filter_getinfoproc *filter, const char **fork) -{ - int i; - int lastunnamed = 0; - char *s; - char *name = nullptr; - char *value = nullptr; - static char buf[256]; - - if (filter) - *filter = nullptr; - if (fork) - *fork = nullptr; - - for (i = 0; i < argc; i++) - { - /* Named or unamed arg */ - if ((argv[i][0] != '-') || (argv[i][1] != '-')) - { - /* Unnamed */ - if (i >= maxunnamed) - goto error; /* Too many unnamed */ - lastunnamed = i + 1; - } - else - { - /* Named */ - name = argv[i] + 2; - s = strchr(name, '='); - if (!s) - goto error; - *s = 0; - value = s + 1; - - if (!strcmp(name, "filter")) - { - /* filter option */ - if (!filter) - goto error; /* this command doesn't use filters */ - if (*filter) - goto optionalreadyspecified; - *filter = filter_lookup(value); - if (!(*filter)) - goto filternotfound; - - } - else if (!strcmp(name, "fork")) - { - /* fork option */ - if (!fork) - goto error; /* this command doesn't use filters */ - if (*fork) - goto optionalreadyspecified; - - snprintf(buf, std::size(buf), "%s", value); - *fork = buf; - } - else - { - /* Other named option */ - if (i < minunnamed) - goto error; /* Too few unnamed */ - - util::option_resolution::entry *entry = resolution->find(name); - if (entry->option_type() == util::option_guide::entry::option_type::ENUM_BEGIN) - { - const util::option_guide::entry *enum_value; - for (enum_value = entry->enum_value_begin(); enum_value != entry->enum_value_end(); enum_value++) - { - if (!strcmp (enum_value->identifier(), value)) - { - entry->set_value(enum_value->parameter()); - break; - } - } - if (enum_value == entry->enum_value_end()) - goto error; - } - else - entry->set_value(value); - } - } - } - return lastunnamed; - -filternotfound: - util::stream_format(std::wcerr, L"%s: Unknown filter type\n", wstring_from_utf8(value)); - return -1; - -optionalreadyspecified: - util::stream_format(std::wcerr, L"Cannot specify multiple %ss\n", wstring_from_utf8(name)); - return -1; - -error: - util::stream_format(std::wcerr, L"%s: Unrecognized option\n", wstring_from_utf8(argv[i])); - return -1; -} - - - -void reporterror(imgtoolerr_t err, const struct command *c, const char *format, const char *imagename, - const char *filename, const char *newname, util::option_resolution *opts) -{ - const char *src = "imgtool"; - const char *err_name; - - err_name = imgtool_error(err); - - switch(ERRORSOURCE(err)) { - case IMGTOOLERR_SRC_MODULE: - src = format; - break; - case IMGTOOLERR_SRC_FUNCTIONALITY: - src = c->name; - break; - case IMGTOOLERR_SRC_IMAGEFILE: - src = imagename; - break; - case IMGTOOLERR_SRC_FILEONIMAGE: - src = filename; - break; - case IMGTOOLERR_SRC_NATIVEFILE: - src = newname ? newname : filename; - break; - } - fflush(stdout); - fflush(stderr); - - if (!src) - src = c->name; - util::stream_format(std::wcerr, L"%s: %s\n", wstring_from_utf8(src), wstring_from_utf8(err_name)); -} - - - -static const char *interpret_filename(const char *filename) -{ - if (!strcmp(filename, "??BOOT??") - || !strcmp(filename, "\'??BOOT??\'") - || !strcmp(filename, "\"??BOOT??\"")) - filename = FILENAME_BOOTBLOCK; - return filename; -} - - - -// ---------------------------------------------------------------------- - -static int cmd_dir(const struct command *c, int argc, char *argv[]) -{ - imgtoolerr_t err; - int total_count, total_size, freespace_err; - uint64_t freespace; - imgtool::image::ptr image; - imgtool::partition::ptr partition; - imgtool::directory::ptr imgenum; - imgtool_dirent ent; - char last_modified[19]; - std::string path; - int partition_index = 0; - std::string info; - - // build the separator - const int columnwidth_filename = 30; - const int columnwidth_filesize = 8; - const int columnwidth_attributes = 15; - const int columnwidth_lastmodified = 18; - std::string separator = std::string(columnwidth_filename, '-') + " " - + std::string(columnwidth_filesize, '-') + " " - + std::string(columnwidth_attributes, '-') + " " - + std::string(columnwidth_lastmodified, '-'); - - // attempt to open image - err = imgtool::image::open(argv[0], argv[1], OSD_FOPEN_READ, image); - if (err) - goto done; - - /* attempt to open partition */ - err = imgtool::partition::open(*image, partition_index, partition); - if (err) - goto done; - - path = argc > 2 ? argv[2] : ""; - - err = imgtool::directory::open(*partition, path, imgenum); - if (err) - goto done; - - memset(&ent, 0, sizeof(ent)); - last_modified[0] = '\0'; - total_count = 0; - total_size = 0; - - util::stream_format(std::wcout, L"Contents of %s:%s\n", wstring_from_utf8(argv[1]), wstring_from_utf8(path)); - - info = image->info(); - if (!info.empty()) - util::stream_format(std::wcout, L"%s\n", wstring_from_utf8(info)); - - util::stream_format(std::wcout, L"%s\n", wstring_from_utf8(separator)); - - while (((err = imgenum->get_next(ent)) == 0) && !ent.eof) - { - std::string filesize_string = ent.directory - ? "" - : util::string_format("%u", (unsigned int) ent.filesize); - - if (!ent.lastmodified_time.empty()) - { - std::tm t = ent.lastmodified_time.localtime(); - strftime(last_modified, sizeof(last_modified), "%d-%b-%y %H:%M:%S", &t); - } - - if (ent.hardlink) - strcat(ent.filename, " "); - - util::stream_format(std::wcout, - L"%*s %*s %*s %*s\n", - -columnwidth_filename, wstring_from_utf8(ent.filename), - columnwidth_filesize, wstring_from_utf8(filesize_string), - columnwidth_attributes, wstring_from_utf8(ent.attr), - columnwidth_lastmodified, wstring_from_utf8(last_modified)); - - if (ent.softlink[0] != '\0') - util::stream_format(std::wcout, L"-> %s\n", wstring_from_utf8(ent.softlink)); - - 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)); - } - - freespace_err = partition->get_free_space(freespace); - - if (err) - goto done; - - util::stream_format(std::wcout, L"%s\n", wstring_from_utf8(separator)); - util::stream_format(std::wcout, L"%8i File(s) %8i bytes", total_count, total_size); - if (!freespace_err) - util::stream_format(std::wcout, L" %8u bytes free\n", (unsigned int)freespace); - else - util::stream_format(std::wcout, L"\n"); - -done: - if (err) - reporterror(err, c, argv[0], argv[1], nullptr, nullptr, nullptr); - return err ? -1 : 0; -} - - - -static int cmd_get(const struct command *c, int argc, char *argv[]) -{ - imgtoolerr_t err; - imgtool::image::ptr image; - imgtool::partition::ptr partition; - const char *filename; - char *new_filename; - int unnamedargs = 0; - filter_getinfoproc filter; - const char *fork; - int partition_index = 0; - - err = imgtool::image::open(argv[0], argv[1], OSD_FOPEN_READ, image); - if (err) - goto done; - - err = imgtool::partition::open(*image, partition_index, partition); - if (err) - goto done; - - filename = interpret_filename(argv[2]); - - unnamedargs = parse_options(argc, argv, 3, 4, nullptr, &filter, &fork); - if (unnamedargs < 0) - goto done; - - new_filename = (unnamedargs == 4) ? argv[3] : nullptr; - - err = partition->get_file(filename, fork, new_filename, filter); - if (err) - goto done; - - err = IMGTOOLERR_SUCCESS; - -done: - if (err) - reporterror(err, c, argv[0], argv[1], argv[2], argv[3], nullptr); - return (err || (unnamedargs < 0)) ? -1 : 0; -} - - - -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; - const imgtool_module *module; - std::unique_ptr resolution; - const char *fork; - const char *new_filename; - char **filename_list; - int filename_count; - int partition_index = 0; - const util::option_guide *writefile_optguide; - const char *writefile_optspec; - - module = imgtool_find_module(argv[0]); - if (!module) - { - err = (imgtoolerr_t)(IMGTOOLERR_MODULENOTFOUND | IMGTOOLERR_SRC_MODULE); - goto done; - } - - /* ugh I hate the way this function is set up, this is because the - * arguments depend on the partition; something that requires some - * rudimentary parsing */ - if (argc >= 2) - { - /* open up the image */ - err = imgtool::image::open(module, argv[1], OSD_FOPEN_RW, image); - if (err) - goto done; - - /* open up the partition */ - err = imgtool::partition::open(*image, partition_index, partition); - if (err) - goto done; - - writefile_optguide = (const util::option_guide *) partition->get_info_ptr(IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE); - writefile_optspec = (const char *)partition->get_info_ptr(IMGTOOLINFO_STR_WRITEFILE_OPTSPEC); - - if (writefile_optguide && writefile_optspec) - { - try { resolution.reset(new util::option_resolution(*writefile_optguide)); } - catch (...) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto done; - } - resolution->set_specification(writefile_optspec); - } - } - - unnamedargs = parse_options(argc, argv, 4, 0xffff, resolution.get(), &filter, &fork); - if (unnamedargs < 0) - return -1; - - /* pick out which args are filenames, and which one is the destination */ - new_filename = interpret_filename(argv[unnamedargs - 1]); - filename_list = &argv[2]; - filename_count = unnamedargs - 3; - - /* loop through the filenames, and put them */ - for (i = 0; i < filename_count; i++) - { - filename = filename_list[i]; - util::stream_format(std::wcout, L"Putting file '%s'...\n", wstring_from_utf8(filename)); - err = partition->put_file(new_filename, fork, filename, resolution.get(), filter); - if (err) - goto done; - } - -done: - if (err) - reporterror(err, c, argv[0], argv[1], filename, nullptr, resolution.get()); - return err ? -1 : 0; -} - - - -static int cmd_getall(const struct command *c, int argc, char *argv[]) -{ - imgtoolerr_t err; - imgtool::image::ptr image; - imgtool::partition::ptr partition; - imgtool::directory::ptr imgenum; - imgtool_dirent ent; - filter_getinfoproc filter; - int unnamedargs; - const char *path = ""; - int arg; - int partition_index = 0; - - err = imgtool::image::open(argv[0], argv[1], OSD_FOPEN_READ, image); - if (err) - goto done; - - err = imgtool::partition::open(*image, partition_index, partition); - if (err) - goto done; - - arg = 2; - if ((argc > 2) && (argv[2][0] != '-')) - { - path = argv[arg++]; - } - - unnamedargs = parse_options(argc, argv, arg, arg, nullptr, &filter, nullptr); - if (unnamedargs < 0) - goto done; - - err = imgtool::directory::open(*partition, path, imgenum); - 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); - - err = partition->get_file(ent.filename, nullptr, nullptr, filter); - if (err) - goto done; - } - -done: - if (err) - reporterror(err, c, argv[0], argv[1], nullptr, nullptr, nullptr); - return err ? -1 : 0; -} - - - -static int cmd_del(const struct command *c, int argc, char *argv[]) -{ - imgtoolerr_t err; - imgtool::image::ptr image; - imgtool::partition::ptr partition; - int partition_index = 0; - - err = imgtool::image::open(argv[0], argv[1], OSD_FOPEN_RW, image); - if (err) - goto done; - - err = imgtool::partition::open(*image, partition_index, partition); - if (err) - goto done; - - err = partition->delete_file(argv[2]); - if (err) - goto done; - -done: - if (err) - reporterror(err, c, argv[0], argv[1], argv[2], nullptr, nullptr); - return err ? -1 : 0; -} - - - -static int cmd_mkdir(const struct command *c, int argc, char *argv[]) -{ - imgtoolerr_t err; - imgtool::image::ptr image; - imgtool::partition::ptr partition; - int partition_index = 0; - - err = imgtool::image::open(argv[0], argv[1], OSD_FOPEN_RW, image); - if (err) - goto done; - - err = imgtool::partition::open(*image, partition_index, partition); - if (err) - goto done; - - err = partition->create_directory(argv[2]); - if (err) - goto done; - -done: - if (err) - reporterror(err, c, argv[0], argv[1], argv[2], nullptr, nullptr); - return err ? -1 : 0; -} - - - -static int cmd_rmdir(const struct command *c, int argc, char *argv[]) -{ - imgtoolerr_t err; - imgtool::image::ptr image; - imgtool::partition::ptr partition; - int partition_index = 0; - - err = imgtool::image::open(argv[0], argv[1], OSD_FOPEN_RW, image); - if (err) - goto done; - - err = imgtool::partition::open(*image, partition_index, partition); - if (err) - goto done; - - err = partition->delete_directory(argv[2]); - if (err) - goto done; - -done: - if (err) - reporterror(err, c, argv[0], argv[1], argv[2], nullptr, nullptr); - return err ? -1 : 0; -} - - - -static int cmd_identify(const struct command *c, int argc, char *argv[]) -{ - imgtool_module *modules[128]; - imgtoolerr_t err; - int i; - - err = imgtool::image::identify_file(argv[0], modules, std::size(modules)); - if (err) - { - reporterror(err, c, nullptr, argv[0], nullptr, nullptr, nullptr); - return -1; - } - else - { - for (i = 0; modules[i]; i++) - { - util::stream_format(std::wcout, L"%.16s %s\n", wstring_from_utf8(modules[i]->name), wstring_from_utf8(modules[i]->description)); - } - - return 0; - } -} - - - -static int cmd_create(const struct command *c, int argc, char *argv[]) -{ - imgtoolerr_t err; - int unnamedargs; - const imgtool_module *module; - std::unique_ptr resolution; - - module = imgtool_find_module(argv[0]); - if (!module) - { - err = (imgtoolerr_t)(IMGTOOLERR_MODULENOTFOUND | IMGTOOLERR_SRC_MODULE); - goto error; - } - - if (module->createimage_optguide && !module->createimage_optspec.empty()) - { - try { resolution.reset(new util::option_resolution(*module->createimage_optguide)); } - catch (...) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto error; - } - resolution->set_specification(module->createimage_optspec.c_str()); - } - - unnamedargs = parse_options(argc, argv, 2, 3, resolution.get(), nullptr, nullptr); - if (unnamedargs < 0) - return -1; - - err = imgtool::image::create(module, argv[1], resolution.get()); - if (err) - goto error; - - return 0; - -error: - reporterror(err, c, argv[0], argv[1], nullptr, nullptr, nullptr); - return -1; -} - - - -static int cmd_readsector(const struct command *c, int argc, char *argv[]) -{ - imgtoolerr_t err; - std::unique_ptr img; - imgtool::stream::ptr stream; - std::vector buffer; - uint32_t track, head, sector; - - /* attempt to open image */ - err = imgtool::image::open(argv[0], argv[1], OSD_FOPEN_READ, img); - if (err) - goto done; - - track = atoi(argv[2]); - head = atoi(argv[3]); - sector = atoi(argv[4]); - - err = img->read_sector(track, head, sector, buffer); - if (err) - goto done; - - stream = imgtool::stream::open(argv[5], OSD_FOPEN_WRITE); - if (!stream) - { - err = (imgtoolerr_t)(IMGTOOLERR_FILENOTFOUND | IMGTOOLERR_SRC_NATIVEFILE); - goto done; - } - - stream->write(&buffer[0], buffer.size()); - -done: - if (err) - reporterror(err, c, argv[0], argv[1], nullptr, nullptr, nullptr); - return err ? -1 : 0; -} - - - -static int cmd_writesector(const struct command *c, int argc, char *argv[]) -{ - imgtoolerr_t err; - std::unique_ptr img; - imgtool::stream::ptr stream; - std::vector buffer; - uint32_t size, track, head, sector; - - // attempt to open image - err = imgtool::image::open(argv[0], argv[1], OSD_FOPEN_RW, img); - if (err) - goto done; - - track = atoi(argv[2]); - head = atoi(argv[3]); - sector = atoi(argv[4]); - - stream = imgtool::stream::open(argv[5], OSD_FOPEN_READ); - if (!stream) - { - err = (imgtoolerr_t)(IMGTOOLERR_FILENOTFOUND | IMGTOOLERR_SRC_NATIVEFILE); - goto done; - } - - size = (uint32_t) stream->size(); - - buffer.resize(size); - - stream->read(&buffer[0], size); - - err = img->write_sector(track, head, sector, &buffer[0], size); - if (err) - goto done; - -done: - if (err) - reporterror(err, c, argv[0], argv[1], nullptr, nullptr, nullptr); - return err ? -1 : 0; -} - - - -static int cmd_listformats(const struct command *c, int argc, char *argv[]) -{ - util::stream_format(std::wcout, L"Image formats supported by imgtool:\n\n"); - - for (const auto &module : imgtool_get_modules()) - { - util::stream_format(std::wcout, L" %-25s%s\n", wstring_from_utf8(module->name), wstring_from_utf8(module->description)); - } - - return 0; -} - - - -static int cmd_listfilters(const struct command *c, int argc, char *argv[]) -{ - int i; - - util::stream_format(std::wcout, L"Filters supported by imgtool:\n\n"); - - for (i = 0; filters[i]; i++) - { - util::stream_format(std::wcout, L" %-11s%s\n", - wstring_from_utf8(filter_get_info_string(filters[i], FILTINFO_STR_NAME)), - wstring_from_utf8(filter_get_info_string(filters[i], FILTINFO_STR_HUMANNAME))); - } - - return 0; -} - -static void listoptions(const util::option_guide &opt_guide, const char *opt_spec) -{ - util::option_resolution resolution(opt_guide); - resolution.set_specification(opt_spec); - - util::stream_format(std::wcout, L"Option Allowed values Description\n"); - util::stream_format(std::wcout, L"---------------- ------------------------------ -----------\n"); - - for (auto iter = resolution.entries_begin(); iter != resolution.entries_end(); iter++) - { - const util::option_resolution::entry &entry = *iter; - std::stringstream description_buffer; - - std::string opt_name = util::string_format("--%s", entry.identifier()); - const char *opt_desc = entry.display_name(); - - // is this option relevant? - if (!strchr(opt_spec, entry.parameter())) - continue; - - switch (entry.option_type()) - { - case util::option_guide::entry::option_type::INT: - for (const auto &range : entry.ranges()) - { - if (!description_buffer.str().empty()) - description_buffer << "/"; - - if (range.min == range.max) - util::stream_format(description_buffer, "%d", range.min); - else - util::stream_format(description_buffer, "%d-%d", range.min, range.max); - } - break; - - case util::option_guide::entry::option_type::ENUM_BEGIN: - for (auto enum_value = entry.enum_value_begin(); enum_value != entry.enum_value_end(); enum_value++) - { - if (!description_buffer.str().empty()) - description_buffer << '/'; - description_buffer << enum_value->identifier(); - } - break; - - case util::option_guide::entry::option_type::STRING: - description_buffer << "(string)"; - break; - - default: - assert(0); - break; - } - - util::stream_format(std::wcout, L"%16s %-30s %s\n", - wstring_from_utf8(opt_name), - wstring_from_utf8(description_buffer.str()), - wstring_from_utf8(opt_desc)); - } -} - - - -static int cmd_listdriveroptions(const struct command *c, int argc, char *argv[]) -{ - const imgtool_module *mod; - const util::option_guide *opt_guide; - const char *opt_spec; - - mod = imgtool_find_module(argv[0]); - if (!mod) - { - reporterror((imgtoolerr_t)(IMGTOOLERR_MODULENOTFOUND|IMGTOOLERR_SRC_MODULE), c, argv[0], nullptr, nullptr, nullptr, nullptr); - return -1; - } - - util::stream_format(std::wcout, L"Driver specific options for module '%s':\n\n", wstring_from_utf8(argv[0])); - - /* list write options */ - opt_guide = (const util::option_guide *) imgtool_get_info_ptr(&mod->imgclass, IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE); - opt_spec = imgtool_get_info_string(&mod->imgclass, IMGTOOLINFO_STR_WRITEFILE_OPTSPEC); - if (opt_guide) - { - util::stream_format(std::wcout, L"Image specific file options (usable on the 'put' command):\n\n"); - listoptions(*opt_guide, opt_spec); - util::stream_format(std::wcout, L"\n"); - } - else - { - util::stream_format(std::wcout, L"No image specific file options\n\n"); - } - - /* list create options */ - opt_guide = mod->createimage_optguide; - 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.c_str()); - util::stream_format(std::wcout, L"\n"); - } - else - { - util::stream_format(std::wcout, L"No image specific creation options\n\n"); - } - - return 0; -} - - - -/* ----------------------------------------------------------------------- */ - -static const struct command cmds[] = -{ - { "create", cmd_create, " [--(createoption)=value]", 2, 8, 0}, - { "dir", cmd_dir, " [path]", 2, 3, 0 }, - { "get", cmd_get, " [newname] [--filter=filter] [--fork=fork]", 3, 6, 0 }, - { "put", cmd_put, " ... [--(fileoption)==value] [--filter=filter] [--fork=fork]", 3, 0xffff, 0 }, - { "getall", cmd_getall, " [path] [--filter=filter]", 2, 3, 0 }, - { "del", cmd_del, " ...", 3, 3, 1 }, - { "mkdir", cmd_mkdir, " ", 3, 3, 0 }, - { "rmdir", cmd_rmdir, " ...", 3, 3, 1 }, - { "readsector", cmd_readsector, " ", 6, 6, 0 }, - { "writesector", cmd_writesector, " ", 6, 6, 0 }, - { "identify", cmd_identify, "", 1, 1 }, - { "listformats", cmd_listformats, nullptr, 0, 0, 0 }, - { "listfilters", cmd_listfilters, nullptr, 0, 0, 0 }, - { "listdriveroptions", cmd_listdriveroptions, "", 1, 1, 0 } -}; - - -// ---------------------------------------------------------------------- - -int main(int argc, char *argv[]) -{ - int i; - int result; - const struct command *c; - const char *sample_format = "coco_jvc_rsdos"; - std::string cmdname(core_filename_extract_base(argv[0])); - -#ifdef _WIN32 - _setmode(_fileno(stdout), _O_U8TEXT); -#endif // _WIN32 - -#ifdef MAME_DEBUG - if (imgtool_validitychecks()) - return -1; -#endif // MAME_DEBUG - - // convert arguments to UTF-8 - std::vector args = osd_get_command_line(argc, argv); - argv = (char **)alloca(sizeof(char *) * args.size()); - for (i = 0; i < args.size(); i++) - argv[i] = (char *)args[i].c_str(); - - util::stream_format(std::wcout, L"\n"); - - if (argc > 1) - { - /* figure out what command they are running, and run it */ - for (i = 0; i < std::size(cmds); i++) - { - c = &cmds[i]; - if (!core_stricmp(c->name, argv[1])) - { - /* check argument count */ - if (c->minargs > (argc - 2)) - goto cmderror; - - /* initialize the imgtool core */ - imgtool_init(true, nullptr); - - if (c->lastargrepeats && (argc > c->maxargs)) - { - for (i = c->maxargs+1; i < argc; i++) - { - argv[c->maxargs+1] = argv[i]; - - result = c->cmdproc(c, c->maxargs, argv + 2); - if (result) - goto done; - } - result = 0; - goto done; - } - else - { - if ((c->maxargs > 0) && (c->maxargs < (argc - 2))) - goto cmderror; - - result = c->cmdproc(c, argc - 2, argv + 2); - goto done; - } - } - } - } - - // Usage - util::stream_format(std::wcerr, L"imgtool - Generic image manipulation tool for use with MAME\n\n"); - for (i = 0; i < std::size(cmds); i++) - { - writeusage(std::wcerr, (i == 0), &cmds[i], argv); - } - util::stream_format(std::wcerr, L"\n is the image format, e.g. %s\n", wstring_from_utf8(sample_format)); - util::stream_format(std::wcerr, L" is the image filename; can specify a ZIP file for image name\n"); - - util::stream_format(std::wcerr, L"\nExample usage:\n"); - util::stream_format(std::wcerr, L"\t%s dir %s myimageinazip.zip\n", wstring_from_utf8(cmdname), wstring_from_utf8(sample_format)); - util::stream_format(std::wcerr, L"\t%s get %s myimage.dsk myfile.bin mynewfile.txt\n", wstring_from_utf8(cmdname), wstring_from_utf8(sample_format)); - util::stream_format(std::wcerr, L"\t%s getall %s myimage.dsk\n", wstring_from_utf8(cmdname), wstring_from_utf8(sample_format)); - result = 0; - goto done; - -cmderror: - writeusage(std::wcout, 1, &cmds[i], argv); - result = -1; - -done: - imgtool_exit(); - return result; -} diff --git a/src/tools/imgtool/main.h b/src/tools/imgtool/main.h deleted file mode 100644 index 70cb43e..0000000 --- a/src/tools/imgtool/main.h +++ /dev/null @@ -1,20 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -#include "imgtool.h" - -struct command -{ - const char *name; - int (*cmdproc)(const struct command *c, int argc, char *argv[]); - const char *usage; - int minargs; - int maxargs; - int lastargrepeats; -}; - -void reporterror(imgtoolerr_t err, const struct command *c, const char *format, const char *imagename, - const char *filename, const char *newname, util::option_resolution *opts); - -#ifdef MAME_DEBUG -int cmd_testsuite(struct command *c, int argc, char *argv[]); -#endif diff --git a/src/tools/imgtool/modules.cpp b/src/tools/imgtool/modules.cpp deleted file mode 100644 index de1595c..0000000 --- a/src/tools/imgtool/modules.cpp +++ /dev/null @@ -1,104 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/*************************************************************************** - - modules.c - - List of Imgtool modules - -***************************************************************************/ - -#include "modules.h" - -#ifndef MODULES_RECURSIVE -#define MODULES_RECURSIVE - -/* step 1: declare all external references */ -#define MODULE(name) extern void name##_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info); -#include "modules.cpp" -#undef MODULE - -/* step 2: define the modules[] array */ -#define MODULE(name) name##_get_info, -static void (*const modules[])(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info) = -{ -#include "modules.cpp" -}; - -/* step 3: declare imgtool_create_canonical_library() */ -imgtoolerr_t imgtool_create_canonical_library(bool omit_untested, std::unique_ptr &library) -{ - /* list of modules that we drop */ - static const char *const irrelevant_modules[] = - { - "coco_os9_rsdos" - }; - - library.reset(new imgtool::library()); - if (!library) - return IMGTOOLERR_OUTOFMEMORY; - - // create all modules - for (auto &module : modules) - library->add(module); - - // remove irrelevant modules - 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) - { - for (auto &module : library->modules()) - { - if (module->writing_untested) - { - module->write_sector = nullptr; - } - if (module->creation_untested) - { - module->create = nullptr; - module->createimage_optguide = nullptr; - module->createimage_optspec.clear(); - } - } - } - - return IMGTOOLERR_SUCCESS; -} - - -#else /* MODULES_RECURSIVE */ - -MODULE(amiga_floppy) -MODULE(concept) -MODULE(mac_mfs) -MODULE(mac_hfs) -MODULE(hd) -MODULE(rsdos) -MODULE(dgndos) -MODULE(vzdos) -MODULE(os9) -MODULE(ti99_old) -MODULE(ti99_v9t9) -MODULE(ti99_pc99fm) -MODULE(ti99_pc99mfm) -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) -MODULE(cybiko) -MODULE(cybikoxt) -MODULE(psion) -MODULE(bml3) -MODULE(hp48) -MODULE(hp9845_tape) -MODULE(hp85_tape) -MODULE(rt11) - -#endif /* MODULES_RECURSIVE */ diff --git a/src/tools/imgtool/modules.h b/src/tools/imgtool/modules.h deleted file mode 100644 index d58b5af..0000000 --- a/src/tools/imgtool/modules.h +++ /dev/null @@ -1,18 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/**************************************************************************** - - modules.h - - Code that creates the "canonical" Imgtool library - -****************************************************************************/ - -#ifndef MODULES_H -#define MODULES_H - -#include "library.h" - -imgtoolerr_t imgtool_create_canonical_library(bool omit_untested, std::unique_ptr &library); - -#endif /* MODULES_H */ diff --git a/src/tools/imgtool/modules/amiga.cpp b/src/tools/imgtool/modules/amiga.cpp deleted file mode 100644 index aa5cc26..0000000 --- a/src/tools/imgtool/modules/amiga.cpp +++ /dev/null @@ -1,2420 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Dirk Best -/**************************************************************************** - - amiga.cpp - - Amiga floppies - -****************************************************************************/ - - -/***************************************************************************** - Includes -*****************************************************************************/ - -#include "imgtool.h" -#include "charconv.h" -#include "iflopimg.h" - -#include "formats/imageutl.h" -#include "corestr.h" -#include "opresolv.h" - -#include -#include -#include - - - -/***************************************************************************** - Data structures -*****************************************************************************/ - - -#define BSIZE (512) /* Block size is always 512 bytes for floppies */ -#define TSIZE ((BSIZE/4) - 56) /* Size of data tables */ -#define MSIZE ((BSIZE/4) - 1) /* Size of bitmaps */ - - -enum disk_type -{ - DT_UNKNOWN = -1, - DT_OFS = 0, - DT_FFS = 1, - DT_OFS_INTL = 2, - DT_FFS_INTL = 3, - DT_OFS_INTL_DIRC = 4, - DT_FFS_INTL_DIRC = 5 -}; - - -enum -{ - T_INVALID = 0, - T_HEADER = 2, - T_DATA = 8, - T_LIST = 16, - T_DIRCACHE = 33 -}; - - -enum sec_type -{ - ST_INVALID = 0, - ST_ROOT = 1, - ST_USERDIR = 2, - ST_FILE = -3, - ST_LINKFILE = -4, - ST_LINKDIR = 4, - ST_SOFTLINK = 3 -}; - - -struct amiga_date -{ - uint32_t days; /* days since 1 jan 78 */ - uint32_t mins; /* minutes past midnight */ - uint32_t ticks; /* ticks (1/50 sec) past last minute */ -}; - - -struct root_block -{ - uint32_t ht_size; /* Hash table size in long */ - uint32_t chksum; /* Rootblock checksum */ - uint32_t ht[TSIZE]; /* Hash table (entry block number) */ - uint32_t bm_flag; /* bitmap flag, -1 means VALID */ - uint32_t bm_pages[25]; /* bitmap blocks pointers (first one at bm_pages[0]) */ - amiga_date r; /* last root alteration date */ - uint8_t name_len; /* volume name length */ - uint8_t diskname[30]; /* volume name */ - amiga_date v; /* last disk alteration date */ - amiga_date c; /* filesystem creation date */ - uint32_t extension; /* FFS: first directory cache block, 0 otherwise */ -}; - - -struct bitmap_block -{ - uint32_t chksum; /* checksum, normal algorithm */ - uint32_t map[MSIZE]; /* bitmap */ -}; - - -struct bitmap_ext_block -{ - uint32_t map[MSIZE]; /* bitmap */ - uint32_t next; /* next extension block */ -}; - - -struct file_block -{ - uint32_t header_key; /* self pointer (to this block) */ - uint32_t high_seq; /* number of data block ptr stored here */ - uint32_t first_data; /* first data block ptr */ - uint32_t chksum; /* same algorithm as rootblock */ - uint32_t data_blocks[TSIZE]; /* data blk ptr */ - uint16_t uid; /* UserID */ - uint16_t gid; /* GroupID */ - uint32_t protect; /* protection flags (0 by default) */ - uint32_t byte_size; /* file size in bytes */ - uint8_t comm_len; /* file comment length */ - uint8_t comment[79]; /* comment (max. 79 chars permitted) */ - amiga_date date; /* last change date */ - uint8_t name_len; /* filename length */ - uint8_t filename[30]; /* filename (max. 30 chars permitted) */ - uint32_t real_entry; /* FFS: unused, set to 0 */ - uint32_t next_link; /* FFS: hardlinks chained list (first == newest */ - uint32_t hash_chain; /* next entry ptr with same hash */ - uint32_t parent; /* parent directory */ - uint32_t extension; /* pointer to 1st file extension block */ -}; - - -struct file_ext_block -{ - uint32_t header_key; /* self pointer (to this block) */ - uint32_t high_seq; /* number of data block ptr stored here */ - uint32_t chksum; /* same algorithm as rootblock */ - uint32_t data_blocks[TSIZE]; /* data blk ptr */ - uint32_t parent; /* file header block */ - uint32_t extension; /* pointer to next file extension block */ -}; - - -struct data_block -{ - uint32_t header_key; /* self pointer (to this block) */ - uint32_t seq_num; /* file data block number */ - uint32_t data_size; /* data size */ - uint32_t next_data; /* next data block ptr */ - uint32_t chksum; /* checksum, rootblock algorithm */ - uint8_t data[BSIZE-24]; /* file data */ -}; - - -struct dir_block -{ - uint32_t header_key; /* self pointer (to this block) */ - uint32_t chksum; /* same algorithm as rootblock */ - uint32_t ht[TSIZE]; /* hash table (entry block number) */ - uint8_t uid; /* UserID */ - uint8_t gid; /* GroupID */ - uint32_t protect; /* protection flags (0 by default) */ - uint8_t comm_len; /* file comment length */ - uint8_t comment[79]; /* comment (max. 79 chars permitted) */ - amiga_date date; /* last access date */ - uint8_t name_len; /* directory name length */ - uint8_t dirname[30]; /* directory name (max. 30 chars permitted) */ - uint32_t next_link; /* FFS: hardlinks chained list (first == newest */ - uint32_t hash_chain; /* next entry ptr with same hash */ - uint32_t parent; /* parent directory */ - uint32_t extension; /* FFS: first directory cache block */ -}; - - -struct hardlink_block -{ - uint32_t header_key; /* self pointer (to this block) */ - uint32_t chksum; /* same algorithm as rootblock */ - uint32_t protect; /* protection flags (0 by default) */ - uint8_t comm_len; /* file comment length */ - uint8_t comment[79]; /* comment (max. 79 chars permitted) */ - amiga_date date; /* last access date */ - uint8_t name_len; /* hard link name length */ - uint8_t hlname[30]; /* hard link name (max. 30 chars permitted) */ - uint32_t real_entry; /* FFS: pointer to "real" file or directory */ - uint32_t next_link; /* FFS: hardlinks chained list (first == newest */ - uint32_t hash_chain; /* next entry ptr with same hash */ - uint32_t parent; /* parent directory */ - uint32_t sec_type; /* secondary type, ST_LINKFILE/ST_LINKDIR */ -}; - - -struct softlink_block -{ - uint32_t header_key; /* self pointer (to this block) */ - uint32_t chksum; /* same algorithm as rootblock */ - uint8_t symbolic_name[BSIZE-224]; /* path name to referenced object */ - uint32_t protect; /* protection flags (0 by default) */ - uint8_t comm_len; /* file comment length */ - uint8_t comment[79]; /* comment (max. 79 chars permitted) */ - amiga_date date; /* last access date */ - uint8_t name_len; /* soft link name length */ - uint8_t slname[30]; /* soft link name (max. 30 chars permitted) */ - uint32_t hash_chain; /* next entry ptr with same hash */ - uint32_t parent; /* parent directory */ -}; - - -/* Basic Amiga floppy disk image info */ -struct amiga_floppy -{ - imgtool::stream *stream; - uint8_t sectors; -}; - - -/* iterator used to walk through directory entries */ -struct amiga_iterator -{ - unsigned int index; /* current file index */ - int block; /* block number we are iterating */ - uint32_t next_block; /* next block in hash chain */ - int ht_index; /* current index in the hash table */ - unsigned int eof : 1; /* end of file listing reached? */ -}; - - -/***************************************************************************** - Prototypes -*****************************************************************************/ - - -static imgtoolerr_t amiga_image_read_sector(imgtool::image &img, - uint32_t track, uint32_t head, uint32_t sector, void *buf, size_t len); -static imgtoolerr_t amiga_image_read_sector(imgtool::image &img, - uint32_t track, uint32_t head, uint32_t sector, std::vector &buffer); -static imgtoolerr_t amiga_image_write_sector(imgtool::image &img, - uint32_t track, uint32_t head, uint32_t sector, const void *buf, size_t len, int ddam); - - - -/***************************************************************************** - Utility functions -*****************************************************************************/ - - -/* Amiga version of the toupper function */ -static int intl_toupper(int c) -{ - return (c>='a' && c<='z') || (c>=224 && c<=254 && c!=247) ? c - ('a'-'A') : c ; -} - - -/* Amiga filename case insensitive string compare */ -static int intl_stricmp(const char *s1, const char *s2) -{ - for (;;) - { - int c1 = intl_toupper(*s1++); - int c2 = intl_toupper(*s2++); - - if (c1 == 0 || c1 != c2) - return c1 - c2; - } -} - - -/* Calculate the hash value for a filename */ -static int hash_name(const char *name, int intl) -{ - int i, l = strlen(name); - uint32_t hash = l; - - for(i = 0; i < l; i++) - { - hash *= 13; - hash += (uint8_t) (intl ? intl_toupper(name[i]) : toupper(name[i])); - hash &= 0x7ff; - } - - return hash % TSIZE; /* 0 < hash < 71 in case of BSIZE=512 */ -} - - -/* Returns true if year is a leap year */ -static int is_leap(int year) -{ - return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); -} - - -/* Convert amiga time to standard time */ -static imgtool::datetime amiga_crack_time(amiga_date *date) -{ - int month_days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - int year = 1978, month = 1, year_days = 365; /* base date */ - int day = date->days; - - /* first calculate the year */ - while (day >= year_days) - { - day -= year_days; - year_days = is_leap(++year) ? 366 : 365; - } - - /* then the month */ - while(day >= month_days[month-1]) - { - day -= month_days[month-1]; - if (month == 2 && is_leap(year)) - day -= 1; - month++; - } - - // fill the struct with our calculated values - util::arbitrary_datetime dt; - dt.year = year; - dt.month = month; - dt.day_of_month = day; - dt.hour = date->mins / 60; - dt.minute = date->mins % 60; - dt.second = date->ticks / 50; - - return imgtool::datetime(imgtool::datetime::datetime_type::LOCAL, dt); -} - - -/* convert standard time to amiga time */ -static void amiga_setup_time(time_t time, amiga_date *dest) -{ - struct tm t = *localtime(&time); - int year; - - dest->days = 0; - - for (year = 1978; year < t.tm_year + 1900; year++) - { - dest->days += is_leap(year) ? 366 : 365; - } - - dest->days += t.tm_yday; - dest->mins = t.tm_hour * 60 + t.tm_min; - dest->ticks = t.tm_sec * 50; -} - - -/* convert flags to human readable form */ -static void amiga_decode_flags(uint32_t flags, char *dest) -{ - /* test for flags */ - dest[0] = (flags & 0x80) ? 'h' : '-'; - dest[1] = (flags & 0x40) ? 's' : '-'; - dest[2] = (flags & 0x20) ? 'p' : '-'; - dest[3] = (flags & 0x10) ? 'a' : '-'; - dest[4] = (flags & 0x08) ? '-' : 'r'; - dest[5] = (flags & 0x04) ? '-' : 'w'; - dest[6] = (flags & 0x02) ? '-' : 'e'; - dest[7] = (flags & 0x01) ? '-' : 'd'; - dest[8] = '\0'; -} - - -static void copy_integer_array_be(uint32_t *dest, const uint32_t *source, int size) -{ - int i; - - for (i = 0; i < size; i++) - { - dest[i] = big_endianize_int32(source[i]); - } -} - - -/* This function converts an array of UINT32s to an amiga_date */ -static void copy_date_be(amiga_date *dest, const uint32_t *source) -{ - dest->days = big_endianize_int32(source[0]); - dest->mins = big_endianize_int32(source[1]); - dest->ticks = big_endianize_int32(source[2]); -} - - -/* Calculate the block checksum of a byte array */ -static uint32_t block_checksum(uint8_t *buffer, int length) -{ - uint32_t chksum = 0; - int i; - - for (i = 0; i < length/4; i++) - { - chksum += pick_integer_be(buffer, i*4, 4); - } - - return -chksum; -} - - -/* Get Amiga floppy data */ -static amiga_floppy *get_amiga_floppy(imgtool::image &image) -{ - return (amiga_floppy *)image.extra_bytes(); -} - - -/* Returns the total number of blocks in the image */ -static int get_total_blocks(imgtool::image &img) -{ - amiga_floppy *f = get_amiga_floppy(img); - - return 2 * 80 * f->sectors; -} - - -/* Returns track, head and sector for a block */ -static void find_block(amiga_floppy *f, int block, int *track, - int *head, int *sector) -{ - *track = block / f->sectors; - *head = (block - *track * f->sectors) / f->sectors; - *sector = (block - *track * f->sectors) % f->sectors; -} - - -/* Generic read block */ -static imgtoolerr_t read_block(imgtool::image &img, int block, uint8_t *buffer) -{ - imgtoolerr_t ret; - int track, head, sector; - - find_block(get_amiga_floppy(img), block, &track, &head, §or); - - /* get block from image */ - ret = amiga_image_read_sector(img, track, head, sector, buffer, BSIZE); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - - -/* Generic write block */ -static imgtoolerr_t write_block(imgtool::image &img, int block, const uint8_t *buffer) -{ - imgtoolerr_t ret; - int track, head, sector; - - find_block(get_amiga_floppy(img), block, &track, &head, §or); - - /* write block to image */ - ret = amiga_image_write_sector(img, track, head, sector, buffer, BSIZE, 0); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - - -/* Return the type a block */ -static sec_type get_block_type(imgtool::image &img, int block) -{ - imgtoolerr_t ret; - uint8_t buffer[BSIZE]; - - /* get data */ - ret = read_block(img, block, buffer); - if (ret) return ST_INVALID; - - /* return type */ - switch ((int32_t) pick_integer_be(buffer, BSIZE-4, 4)) - { - case 1: return ST_ROOT; - case 2: return ST_USERDIR; - case -3: return ST_FILE; - case -4: return ST_LINKFILE; - case 4: return ST_LINKDIR; - case 3: return ST_SOFTLINK; - default: return ST_INVALID; - } -} - - -/* Read a bitmap block */ -static imgtoolerr_t read_bitmap_block(imgtool::image &img, int block, bitmap_block *bm) -{ - imgtoolerr_t ret; - uint8_t buffer[BSIZE]; - - /* read block */ - ret = read_block(img, block, buffer); - if (ret) return ret; - - /* fill in data */ - bm->chksum = pick_integer_be(buffer, 0, 4); - copy_integer_array_be(bm->map, (uint32_t *) &buffer[4], MSIZE); - - return IMGTOOLERR_SUCCESS; -} - - -/* Write a bitmap block */ -static imgtoolerr_t write_bitmap_block(imgtool::image &img, int block, const bitmap_block *bm) -{ - imgtoolerr_t ret; - uint8_t buffer[BSIZE]; - - /* Setup buffer */ - place_integer_be(buffer, 0, 4, bm->chksum); - copy_integer_array_be((uint32_t *) &buffer[4], bm->map, MSIZE); - - /* write block */ - ret = write_block(img, block, buffer); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - - -#ifdef UNUSED_FUNCTION -/* Read a bitmap extended block */ -static imgtoolerr_t read_bitmap_ext_block(imgtool::image *img, int block, bitmap_ext_block *bm) -{ - imgtoolerr_t ret; - uint8_t buffer[BSIZE]; - - /* read block */ - ret = read_block(img, block, buffer); - if (ret) return ret; - - /* fill in data */ - copy_integer_array_be(bm->map, (uint32_t *) &buffer, MSIZE); - bm->next = pick_integer_be(buffer, BSIZE-4, 4); - - return IMGTOOLERR_SUCCESS; -} -#endif - - -/* Read the root block */ -static imgtoolerr_t read_root_block(imgtool::image &img, root_block *root) -{ - imgtoolerr_t ret; - uint8_t buffer[BSIZE]; - - /* get raw root block from image */ - ret = read_block(img, get_total_blocks(img)/2, buffer); - if (ret) return ret; - - /* 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); - copy_integer_array_be(root->ht, (uint32_t *) &buffer[24], TSIZE); - root->bm_flag = pick_integer_be(buffer, BSIZE-200, 4); - 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); - 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); - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t write_root_block(imgtool::image &img, const root_block *root) -{ - imgtoolerr_t ret; - uint8_t buffer[BSIZE]; - - /* 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); - copy_integer_array_be((uint32_t *) &buffer[24], root->ht, TSIZE); - place_integer_be(buffer, BSIZE-200, 4, 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); - 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); - - /* write root block to image */ - ret = write_block(img, get_total_blocks(img)/2, buffer); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - - -/* Read a file block */ -static imgtoolerr_t read_file_block(imgtool::image &img, int block, file_block *fb) -{ - imgtoolerr_t ret; - uint8_t buffer[BSIZE]; - - /* read block */ - ret = read_block(img, block, buffer); - 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); - 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); - 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); - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t read_file_ext_block(imgtool::image &img, int block, file_ext_block *fe) -{ - imgtoolerr_t ret; - uint8_t buffer[BSIZE]; - - /* read block */ - ret = read_block(img, block, buffer); - 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); - 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); - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t read_data_block(imgtool::image &img, int block, data_block *d) -{ - imgtoolerr_t ret; - uint8_t buffer[BSIZE]; - - /* read block */ - ret = read_block(img, block, buffer); - 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); - memcpy(d->data, &buffer[24], BSIZE-24); - - return IMGTOOLERR_SUCCESS; -} - - -/* Read a directory block */ -static imgtoolerr_t read_dir_block(imgtool::image &img, int block, dir_block *db) -{ - imgtoolerr_t ret; - uint8_t buffer[BSIZE]; - - /* read block */ - ret = read_block(img, block, buffer); - if (ret) return ret; - - /* fill in data */ - db->header_key = pick_integer_be(buffer, 4, 4); - db->chksum = pick_integer_be(buffer, 20, 4); - 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); - 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); - 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); - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t write_dir_block(imgtool::image &img, int block, const dir_block *db) -{ - uint8_t buffer[BSIZE]; - - /* Setup buffer */ - 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); - 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); - - /* Write block to disk */ - return write_block(img, block, buffer); -} - - -static imgtoolerr_t read_hardlink_block(imgtool::image &img, int block, hardlink_block *hl) -{ - imgtoolerr_t ret; - uint8_t buffer[BSIZE]; - - /* read block */ - ret = read_block(img, block, buffer); - 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); - 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); - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t read_softlink_block(imgtool::image &img, int block, softlink_block *sl) -{ - imgtoolerr_t ret; - uint8_t buffer[BSIZE]; - - /* read block */ - ret = read_block(img, block, buffer); - if (ret) return ret; - - /* fill in data */ - sl->header_key = pick_integer_be(buffer, 4, 4); - sl->chksum = pick_integer_be(buffer, 20, 4); - 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); - 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); - - return IMGTOOLERR_SUCCESS; -} - - -/* Returns the disk type */ -static disk_type get_disk_type(imgtool::image &img) -{ - imgtoolerr_t ret; - uint8_t buffer[BSIZE]; - - ret = read_block(img, 0, buffer); - if (ret) return DT_UNKNOWN; - - switch(buffer[3]) - { - case 0: return DT_OFS; - case 1: return DT_FFS; - case 2: return DT_OFS_INTL; - case 3: return DT_FFS_INTL; - case 4: return DT_OFS_INTL_DIRC; - case 5: return DT_FFS_INTL_DIRC; - default: return DT_UNKNOWN; - } -} - - -/* Returns true if the disk is formatted with the FastFileSystem */ -static int is_ffs(imgtool::image &img) -{ - disk_type t = get_disk_type(img); - - return ((t == DT_FFS || - t == DT_FFS_INTL || - t == DT_FFS_INTL_DIRC) ? true : false); -} - - -/* Returns true if the disk uses the international mode */ -static int is_intl(imgtool::image &img) -{ - disk_type t = get_disk_type(img); - - return ((t == DT_OFS_INTL || - t == DT_FFS_INTL || - t == DT_OFS_INTL_DIRC || - 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) -{ - 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) -{ - imgtoolerr_t ret; - - switch (get_block_type(img, block)) - { - case ST_USERDIR: - { - dir_block dir; - - /* get the directory block */ - ret = read_dir_block(img, block, &dir); - if (ret) return ret; - - /* copy data */ - memcpy(ht, &dir.ht, TSIZE*4); - - return IMGTOOLERR_SUCCESS; - } - - case ST_ROOT: - { - root_block root; - - /* get the root block */ - ret = read_root_block(img, &root); - if (ret) return ret; - - /* copy data */ - memcpy(ht, &root.ht, TSIZE*4); - - return IMGTOOLERR_SUCCESS; - } - - default: - return IMGTOOLERR_UNEXPECTED; - } -} - - -static imgtoolerr_t set_hash_table(imgtool::image &img, int block, const uint32_t *ht) -{ - uint8_t buffer[BSIZE]; - imgtoolerr_t ret; - - /* Read block */ - ret = read_block(img, block, buffer); - if (ret) return ret; - - /* Copy new hash table into it */ - copy_integer_array_be((uint32_t *) &buffer[24], ht, TSIZE); - - /* Write it back again */ - ret = write_block(img, block, buffer); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - -#ifdef UNUSED_FUNCTION -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) -{ - uint8_t buffer[BSIZE]; - imgtoolerr_t ret; - - /* Read the block */ - ret = read_block(img, block, buffer); - if (ret) return ret; - - /* Copy filename out of the buffer */ - memset(dest, 0, 31); - memcpy(dest, &buffer[BSIZE-79], buffer[BSIZE-80]); - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t get_hash_chain(imgtool::image &img, int block, uint32_t *chain) -{ - uint8_t buffer[BSIZE]; - imgtoolerr_t ret; - - /* Read block */ - ret = read_block(img, block, buffer); - if (ret) return ret; - - /* Get chain value */ - *chain = pick_integer_be(buffer, BSIZE-16, 4); - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t set_hash_chain(imgtool::image &img, int block, uint32_t chain) -{ - uint8_t buffer[BSIZE]; - imgtoolerr_t ret; - - /* Read block */ - ret = read_block(img, block, buffer); - if (ret) return ret; - - /* Copy new hash chain value into it */ - place_integer_be(buffer, BSIZE-16, 4, chain); - - /* Write it back again */ - ret = write_block(img, block, buffer); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t walk_hash_chain(imgtool::image &img, const char *path, int start_block, int *prev_block, int *block) -{ - imgtoolerr_t err; - uint32_t hash_chain; - char name[31]; - - /* choose compare function depending on intl mode */ - int (*cmp)(const char *, const char *) = is_intl(img) ? &intl_stricmp : &core_stricmp; - - /* initialize filenames */ - memset(name, 0, sizeof(name)); - - switch (get_block_type(img, start_block)) - { - case ST_USERDIR: - { - dir_block dir; - - /* read block */ - err = read_dir_block(img, start_block, &dir); - if (err) return err; - - /* copy filename string and next hash */ - memcpy(name, dir.dirname, dir.name_len); - hash_chain = dir.hash_chain; - - break; - } - - case ST_FILE: - { - file_block file; - - /* read block */ - err = read_file_block(img, start_block, &file); - if (err) return err; - - /* copy filename string and next hash */ - memcpy(name, file.filename, file.name_len); - hash_chain = file.hash_chain; - - break; - } - - case ST_SOFTLINK: - { - softlink_block sl; - - /* read block */ - err = read_softlink_block(img, start_block, &sl); - if (err) return err; - - /* copy filename string and next hash */ - memcpy(name, sl.slname, sl.name_len); - hash_chain = sl.hash_chain; - - break; - } - - case ST_LINKDIR: - case ST_LINKFILE: - { - hardlink_block hl; - - /* read block */ - err = read_hardlink_block(img, start_block, &hl); - if (err) return err; - - /* copy filename string and next hash */ - memcpy(name, hl.hlname, hl.name_len); - hash_chain = hl.hash_chain; - break; - } - - default: - return IMGTOOLERR_UNEXPECTED; - - } - - /* if we haven't found the right filename but there are linked entries, - * walk up the chain */ - if ((*cmp)(name, path) != 0 && hash_chain != 0) - { - *prev_block = start_block; - return walk_hash_chain(img, path, hash_chain, prev_block, block); - } - - /* found the correct block, return */ - if ((*cmp)(name, path) == 0) - { - *block = start_block; - return IMGTOOLERR_SUCCESS; - } - - /* we should never get here */ - return IMGTOOLERR_UNEXPECTED; -} - - -/* Returns the block number for a dir/file/link entry given as NUL delimited - * list of path parts, for example "dir1\0dir2\0dir3" returns the block number - * for directory "dir3" */ -static imgtoolerr_t find_entry(imgtool::image &img, const char *path, int start_block, int *block) -{ - imgtoolerr_t ret; - const char *next_path; - int current_block, prev; - uint32_t ht[TSIZE]; - - /* get the hash table */ - ret = get_hash_table(img, start_block, ht); - if (ret) return ret; - - /* calculate hash and get block for initial entry */ - current_block = ht[hash_name(path, is_intl(img))]; - - /* check if there was a match in the hash table */ - if (current_block == 0) - { - return IMGTOOLERR_PATHNOTFOUND; - } - - /* walk the linked hash list */ - ret = walk_hash_chain(img, path, current_block, &prev, block); - if (ret) return ret; - - /* follow links */ - switch (get_block_type(img, *block)) - { - case ST_SOFTLINK: - - /* TODO: Softlink support */ - return IMGTOOLERR_UNIMPLEMENTED; - - case ST_LINKDIR: - case ST_LINKFILE: - { - hardlink_block hl; - - ret = read_hardlink_block(img, *block, &hl); - if (ret) return ret; - - *block = hl.real_entry; - - break; - } - - default: - break; - } - - /* get next path part */ - next_path = path + strlen(path) + 1; - - /* if there are more path parts, search the next block */ - if (next_path[0]) - { - return find_entry(img, next_path, *block, block); - } - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t get_block_chksum(imgtool::image &img, int block, uint32_t *chksum, int bitmap) -{ - imgtoolerr_t ret; - uint8_t buffer[BSIZE]; - - /* get block data */ - ret = read_block(img, block, buffer); - if (ret) return ret; - - /* clear old checksum */ - if (bitmap) - { - memset(buffer, 0, 4); - } - else - { - memset(&buffer[20], 0, 4); - } - - /* calulate checksum */ - *chksum = block_checksum(buffer, BSIZE); - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t fix_chksum(imgtool::image &img, int block, int bitmap) -{ - imgtoolerr_t ret; - uint8_t buffer[BSIZE]; - uint32_t chksum; - - /* calculate block checksum */ - ret = get_block_chksum(img, block, &chksum, bitmap); - if (ret) return ret; - - /* read block data */ - ret = read_block(img, block, buffer); - if (ret) return ret; - - /* update checksum */ - if (bitmap) - { - place_integer_be(buffer, 0, 4, chksum); - } - else - { - place_integer_be(buffer, 20, 4, chksum); - } - - /* write back new block data */ - ret = write_block(img, block, buffer); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t fix_block_chksum(imgtool::image &img, int block) -{ - return fix_chksum(img, block, false); -} - - -static imgtoolerr_t fix_bitmap_chksum(imgtool::image &img, int block) -{ - return fix_chksum(img, block, true); -} - - -/* Set a block as used */ -static imgtoolerr_t bitmap_mark(imgtool::image &img, int block, int used) -{ - imgtoolerr_t ret; - bitmap_block bm; - root_block root; - int page; - - block -= 2; /* subtract boot block sectors, 2 only for floppies! */ - - ret = read_root_block(img, &root); - if (ret) return ret; - - /* figure out bitmap block location */ - page = root.bm_pages[block / (MSIZE * 32)]; - - /* get bitmap */ - ret = read_bitmap_block(img, page, &bm); - if (ret) return ret; - - /* subtract pages we skip */ - block -= MSIZE * 32 * (block / (MSIZE * 32)); - - /* mark as used or free */ - if (used) - { - bm.map[block/32] &= ~(1 << block % 32); - } - else - { - bm.map[block/32] |= (1 << block % 32); - } - - /* write changed bitmap block back to disk */ - ret = write_bitmap_block(img, page, &bm); - if (ret) return ret; - - /* update checksum */ - ret = fix_bitmap_chksum(img, page); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t bitmap_mark_used(imgtool::image &img, int block) -{ - return bitmap_mark(img, block, true); -} - - -static imgtoolerr_t bitmap_mark_free(imgtool::image &img, int block) -{ - return bitmap_mark(img, block, false); -} - - -static imgtoolerr_t update_block_modified_date(imgtool::image &img, int block) -{ - uint8_t buffer[BSIZE]; - imgtoolerr_t ret; - amiga_date date; - time_t now; - - ret = read_block(img, block, buffer); - if (ret) return ret; - - /* Set new time */ - time(&now); - 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); - - /* Write block back to disk */ - ret = write_block(img, block, buffer); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t clear_hash_table_entry(imgtool::image &img, int parent, char *filename) -{ - imgtoolerr_t ret; - uint32_t ht[TSIZE], chain; - int index, entry, prev, block; - - ret = get_hash_table(img, parent, ht); - if (ret) return ret; - - /* Calculate hash and get block for initial entry */ - index = hash_name(filename, is_intl(img)); - entry = ht[index]; - - /* Walk the hash chain to get the real entry */ - ret = walk_hash_chain(img, filename, entry, &prev, &block); - if (ret) return ret; - - /* Get chained value from block */ - ret = get_hash_chain(img, block, &chain); - if (ret) return ret; - - /* Check if we need to change the hash table */ - if (entry == block) - { - /* Set new value (might be 0 if there were no linked entries) */ - ht[index] = chain; - - /* Save changed hash table */ - ret = set_hash_table(img, parent, ht); - if (ret) return ret; - - /* Update last modified date */ - ret = update_block_modified_date(img, parent); - if (ret) return ret; - - /* Calculate new checksum */ - ret = fix_block_chksum(img, parent); - if (ret) return ret; - } - else - { - /* Save chained value to previous chain element */ - ret = set_hash_chain(img, prev, chain); - if (ret) return ret; - - /* Calculate new checksum */ - ret = fix_block_chksum(img, prev); - if (ret) return ret; - } - - /* Mark our block as free */ - ret = bitmap_mark_free(img, block); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - - -/* Returns the number of the first bit that is set in the array */ -static int get_first_bit(uint32_t *array, int size) -{ - int i; - - for (i = 0; i < size; i++) - { - if (array[i] != 0) - { - uint32_t v = array[i]; - int c; - - /* get first bit that is set */ - for (c = 0; (v & 1) == 0; c++) v >>= 1; - - /* return bit number */ - return i * 32 + c; - } - } - - return -1; -} - - -#ifdef UNUSED_FUNCTION -static imgtoolerr_t walk_bitmap_ext_blocks(imgtool::image *img, int start, int *block) -{ - imgtoolerr_t ret; - bitmap_ext_block bm_ext; - int bit; - - /* if we don't have a valid block, bail out */ - if (start == 0) - { - return IMGTOOLERR_NOSPACE; - } - - /* get the extended bitmap block */ - ret = read_bitmap_ext_block(img, start, &bm_ext); - if (ret) return ret; - - /* get the first bit that is set in the map */ - bit = get_first_bit(bm_ext.map, MSIZE); - - /* if we found one, return */ - if (bit != -1) - { - *block += bit; - return IMGTOOLERR_SUCCESS; - } - - /* increase on each call */ - *block += MSIZE * 32; - - /* else continue walking the list */ - return walk_bitmap_ext_blocks(img, bm_ext.next, block); -} -#endif - - -/* Searches for a block marked as free - * TODO: bm_ext support for HDs */ -static imgtoolerr_t find_free_block(imgtool::image &img, int *block) -{ - imgtoolerr_t ret; - root_block root; - int i; - - /* get root block */ - ret = read_root_block(img, &root); - if (ret) return ret; - - /* iterate bitmap pointers */ - for (i = 0; i < 25; i++) - { - bitmap_block bm; - - /* get bitmap block pointed to */ - ret = read_bitmap_block(img, root.bm_pages[i], &bm); - if (ret) return ret; - - *block = i * 32 * MSIZE + get_first_bit(bm.map, MSIZE); - - if (*block != -1) - { - *block += 2; - return IMGTOOLERR_SUCCESS; - } - } - - /* if we get here we haven't found a free block */ - return IMGTOOLERR_NOSPACE; -} - - -static imgtoolerr_t add_entry(imgtool::image &img, int parent, int block) -{ - imgtoolerr_t ret; - uint32_t ht[TSIZE]; - char name[31]; - int hash; - - ret = get_blockname(img, block, name); - if (ret) return ret; - - ret = get_hash_table(img, parent, ht); - if (ret) return ret; - - hash = hash_name(name, is_intl(img)); - - /* Check if there is already an entry with that name */ - if (ht[hash] != 0) - { - /* Save the old value to our hash chain */ - ret = set_hash_chain(img, block, ht[hash]); - if (ret) return ret; - } - - /* Write our block number into the table */ - ht[hash] = block; - - /* Write table back to disk */ - ret = set_hash_table(img, parent, ht); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - - -/* Recursively create new directory entries */ -static imgtoolerr_t makedir(imgtool::image &img, const char *path, int parent) -{ - imgtoolerr_t ret; - dir_block dir; - time_t now; - int block; - - if (!path) - { - return IMGTOOLERR_PARAMNEEDED; - } - - if (!path[0]) - { - return IMGTOOLERR_SUCCESS; - } - - /* Get a free block */ - ret = find_free_block(img, &block); - if (ret) return ret; - - /* Initialize entry */ - memset(&dir, 0, sizeof(dir_block)); - - /* Copy data */ - time(&now); - amiga_setup_time(now, &dir.date); - dir.name_len = strlen(path); - memcpy(dir.dirname, path, dir.name_len); - dir.header_key = block; - dir.parent = parent; - - /* Write block */ - ret = write_dir_block(img, block, &dir); - if (ret) return ret; - - /* Fix checksum */ - ret = fix_block_chksum(img, block); - if (ret) return ret; - - /* Link the new entry in the parent */ - ret = add_entry(img, parent, block); - if (ret) return ret; - - /* Mark it as used */ - ret = bitmap_mark_used(img, block); - if (ret) return ret; - - /* Create the next entry */ - return makedir(img, path + strlen(path) + 1, block); -} - - -/* Recursively checks the path parts and creates directories for them */ -static imgtoolerr_t checkdir(imgtool::image &img, const char *path, int parent) -{ - imgtoolerr_t ret; - int block; - char first_part[31]; - - memset(first_part, 0, sizeof(first_part)); - strcpy(first_part, path); - - /* Directories all the way down, bail out */ - if (!path[0]) - { - return IMGTOOLERR_CANNOTUSEPATH; - } - - /* Search for the entry */ - ret = find_entry(img, first_part, parent, &block); - - switch (ret) - { - case IMGTOOLERR_PATHNOTFOUND: - - /* There is no entry with this name yet, so we can just create them */ - return makedir(img, path, parent); - - case IMGTOOLERR_SUCCESS: - - if (get_block_type(img, block) == ST_USERDIR) - { - /* Go down one level */ - return checkdir(img, path + strlen(path) + 1, block); - } - else - { - /* There is an entry but it's not a directory, create it */ - return makedir(img, path, parent); - } - - default: return ret; - } -} - - -/* Writes the file data from the specified block into the stream */ -static imgtoolerr_t write_file_block_data(imgtool::image &img, int block, int size, imgtool::stream &destf) -{ - imgtoolerr_t ret; - uint8_t buffer[BSIZE]; - - /* Check if we even need to write something */ - if (size == 0) - { - return IMGTOOLERR_SUCCESS; - } - - if (is_ffs(img)) - { - /* Get block and read directly into buffer */ - ret = read_block(img, block, buffer); - if (ret) return ret; - } - else - { - data_block db; - uint32_t chksum; - - ret = read_data_block(img, block, &db); - if (ret) return ret; - - /* Verify data checksum */ - ret = get_block_chksum(img, block, &chksum, false); - if (ret) return ret; - - if (db.chksum != chksum) - { - return IMGTOOLERR_CORRUPTFILE; - } - - /* Copy data to buffer */ - memcpy(buffer, db.data, size); - } - - /* Write data to stream */ - if (destf.write(buffer, size) != size) - { - return IMGTOOLERR_WRITEERROR; - } - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t walk_data_block_ptr(imgtool::image &img, uint32_t *ptr, int *filesize, imgtool::stream *destf, bool write) -{ - int i, blocksize = is_ffs(img) ? BSIZE : BSIZE-24; - imgtoolerr_t ret; - - for (i = TSIZE-1; i >= 0; i--) - { - /* We write either blocksize bytes or whats remaining */ - int bytes_left = (*filesize >= blocksize) ? blocksize : *filesize; - - if (write) - { - ret = write_file_block_data(img, ptr[i], bytes_left, *destf); - if (ret) return ret; - } - else - { - ret = bitmap_mark_free(img, ptr[i]); - if (ret) return ret; - } - - *filesize -= bytes_left; - - /* Check if we are finished early */ - if (*filesize == 0) break; - } - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t write_data_block_ptr(imgtool::image &img, uint32_t *ptr, int *filesize, imgtool::stream &destf) -{ - return walk_data_block_ptr(img, ptr, filesize, &destf, true); -} - - -/* Marks all blocks pointed to by the data block pointers as free */ -static imgtoolerr_t clear_data_block_ptr(imgtool::image &img, uint32_t *ptr, int *filesize) -{ - return walk_data_block_ptr(img, ptr, filesize, nullptr, false); -} - - -static imgtoolerr_t walk_file_ext_data(imgtool::image &img, int block, int *filesize, imgtool::stream *destf, int write) -{ - file_ext_block file_ext; - imgtoolerr_t ret; - - /* Get file extension block */ - ret = read_file_ext_block(img, block, &file_ext); - if (ret) return ret; - - /* Write all data pointers in the table */ - ret = walk_data_block_ptr(img, file_ext.data_blocks, filesize, destf, write); - if (ret) return ret; - - /* Check if we are finished */ - if (*filesize != 0) - { - if (file_ext.extension == 0) - { - /* We are not finished, but there are no more extension blocks */ - return IMGTOOLERR_CORRUPTFILE; - } - else - { - /* Write the next file extension block */ - return walk_file_ext_data(img, file_ext.extension, filesize, destf, write); - } - } - - /* Mark ourself as free if we not writing */ - if (!write) - { - ret = bitmap_mark_free(img, block); - if (ret) return ret; - } - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t write_file_ext_data(imgtool::image &img, int block, int *filesize, imgtool::stream *destf) -{ - return walk_file_ext_data(img, block, filesize, destf, true); -} - - -static imgtoolerr_t clear_file_ext_data(imgtool::image &img, int block, int *filesize) -{ - return walk_file_ext_data(img, block, filesize, NULL, false); -} - - -/* Updates the disk alteration date stored in the root block */ -static imgtoolerr_t update_disk_alteration_date(imgtool::image &img) -{ - imgtoolerr_t ret; - root_block root; - time_t now; - - /* Get root block */ - ret = read_root_block(img, &root); - if (ret) return ret; - - /* Get current time */ - time(&now); - amiga_setup_time(now, &root.v); - - /* Write back new root block */ - ret = write_root_block(img, &root); - if (ret) return ret; - - /* And update its checksum */ - ret = fix_block_chksum(img, get_total_blocks(img)/2); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - - -/***************************************************************************** - Imgtool functions -*****************************************************************************/ - - -static imgtoolerr_t amiga_image_open(imgtool::image &img, imgtool::stream::ptr &&stream) -{ - amiga_floppy *f = get_amiga_floppy(img); - uint64_t size = stream->size(); - - f->sectors = size/BSIZE/80/2; - - if (f->sectors != 11 && f->sectors != 22) - { - return IMGTOOLERR_CORRUPTIMAGE; - } - - f->stream = stream.release(); - return IMGTOOLERR_SUCCESS; -} - - -static void amiga_image_exit(imgtool::image &img) -{ - amiga_floppy *f = get_amiga_floppy(img); - if (f->stream) - delete f->stream; -} - - -static void amiga_image_info(imgtool::image &img, std::ostream &stream) -{ - imgtoolerr_t ret; - root_block root; - char info[255]; - time_t t_c, t_v, t_r; - char c[19], v[19], r[19]; - - ret = read_root_block(img, &root); - if (ret) return; - - t_c = amiga_crack_time(&root.c).to_time_t(); - t_v = amiga_crack_time(&root.v).to_time_t(); - t_r = amiga_crack_time(&root.r).to_time_t(); - - strftime(c, sizeof(c), "%d-%b-%y %H:%M:%S", localtime(&t_c)); - strftime(v, sizeof(v), "%d-%b-%y %H:%M:%S", localtime(&t_v)); - strftime(r, sizeof(r), "%d-%b-%y %H:%M:%S", localtime(&t_r)); - - strcpy(info, "Volume name: "); - strncat(info, (char *)root.diskname, root.name_len); - strcat(info, "\nVolume created: "); - strcat(info, c); - strcat(info, "\nVolume modified: "); - strcat(info, v); - strcat(info, "\n Root modified: "); - strcat(info, r); - - stream << info; -} - - -static imgtoolerr_t amiga_image_read_sector(imgtool::image &img, uint32_t track, uint32_t head, uint32_t sector, void *buf, size_t len) -{ - amiga_floppy *f = get_amiga_floppy(img); - - /* skip ahead to the area we want to read */ - f->stream->seek(track * (head+1) * f->sectors * BSIZE + sector * BSIZE, SEEK_CUR); - - if (f->stream->read(buf, len) != len) - { - return IMGTOOLERR_READERROR; - } - - /* reset stream */ - f->stream->seek(0, 0); - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t amiga_image_read_sector(imgtool::image &img, - uint32_t track, uint32_t head, uint32_t sector, std::vector &buffer) -{ - try { buffer.resize(BSIZE); } - catch (std::bad_alloc const &) { return IMGTOOLERR_OUTOFMEMORY; } - - return amiga_image_read_sector(img, track, head, sector, &buffer[0], buffer.size()); -} - - -static imgtoolerr_t amiga_image_write_sector(imgtool::image &img, uint32_t track, uint32_t head, uint32_t sector, const void *buf, size_t len, int ddam) -{ - amiga_floppy *f = get_amiga_floppy(img); - - /* skip ahead to the area we want to write */ - f->stream->seek(track * (head+1) * f->sectors * BSIZE + sector * BSIZE, SEEK_CUR); - - /* write data */ - if (f->stream->write(buf, len) != len) - { - return IMGTOOLERR_WRITEERROR; - } - - /* reset stream */ - f->stream->seek(0, 0); - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t amiga_image_beginenum(imgtool::directory &enumeration, const char *path) -{ - int blocks = get_total_blocks(enumeration.image()); - imgtoolerr_t ret; - amiga_iterator *iter; - - iter = (amiga_iterator *) enumeration.extra_bytes(); - if (!iter) return IMGTOOLERR_OUTOFMEMORY; - - iter->index = 1; - iter->ht_index = 0; - iter->eof = 0; - - if (path[0]) - { - /* search for the directory block, start with the root block */ - ret = find_entry(enumeration.image(), path, blocks/2, &iter->block); - if (ret) return ret; - } - else - { - /* we didn't get a path, use the root directory */ - iter->block = blocks / 2; - } - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t amiga_image_nextenum(imgtool::directory &enumeration, imgtool_dirent &ent) -{ - amiga_iterator *iter = (amiga_iterator *) enumeration.extra_bytes(); - imgtoolerr_t ret; - uint32_t ht[TSIZE]; - int block; - - /* finished listing all entries? */ - if (iter->eof == 1 || iter->ht_index == TSIZE) - { - ent.eof = 1; - return IMGTOOLERR_SUCCESS; - } - - /* get hash table */ - ret = get_hash_table(enumeration.image(), iter->block, ht); - if (ret) return ret; - - /* skip empty hash table entries */ - while (ht[iter->ht_index] == 0) - { - iter->ht_index++; - /* check if we are already at the end */ - if (iter->ht_index == TSIZE) - { - ent.eof = 1; - return IMGTOOLERR_SUCCESS; - } - } - - /* get block number */ - block = (iter->next_block == 0) ? ht[iter->ht_index] : iter->next_block; - - switch (get_block_type(enumeration.image(), block)) - { - case ST_FILE: - { - file_block file; - - /* get block */ - ret = read_file_block(enumeration.image(), block, &file); - if (ret) return ret; - - /* fill directory entry */ - strncpyz(ent.filename, (char *)file.filename, file.name_len + 1); - ent.filesize = file.byte_size; - ent.lastmodified_time = amiga_crack_time(&file.date); - amiga_decode_flags(file.protect, ent.attr); - strncpyz(ent.comment, (char *)file.comment, file.comm_len + 1); - - iter->next_block = file.hash_chain; - - break; - } - - case ST_USERDIR: - { - dir_block dir; - - /* get block */ - ret = read_dir_block(enumeration.image(), block, &dir); - if (ret) return ret; - - /* fill directory entry */ - strncpyz(ent.filename, (char *)dir.dirname, dir.name_len + 1); - ent.lastmodified_time = amiga_crack_time(&dir.date); - amiga_decode_flags(dir.protect, ent.attr); - strncpyz(ent.comment, (char *)dir.comment, dir.comm_len + 1); - ent.directory = 1; - - iter->next_block = dir.hash_chain; - - break; - } - - case ST_SOFTLINK: - { - softlink_block sl; - - /* get block */ - ret = read_softlink_block(enumeration.image(), block, &sl); - if (ret) return ret; - - /* fill directory entry */ - strncpyz(ent.filename, (char *)sl.slname, sl.name_len + 1); - ent.lastmodified_time = amiga_crack_time(&sl.date); - amiga_decode_flags(sl.protect, ent.attr); - strncpyz(ent.comment, (char *)sl.comment, sl.comm_len + 1); - strcpy(ent.softlink, (char *)sl.symbolic_name); - - iter->next_block = sl.hash_chain; - - break; - } - - case ST_LINKDIR: - - ent.directory = 1; - [[fallthrough]]; - - case ST_LINKFILE: - { - hardlink_block hl; - - /* get block */ - ret = read_hardlink_block(enumeration.image(), block, &hl); - if (ret) return ret; - - /* get filesize from linked file */ - if (!ent.directory) - { - file_block file; - ret = read_file_block(enumeration.image(), hl.real_entry, &file); - if (ret) return ret; - ent.filesize = file.byte_size; - } - - /* fill directory entry */ - strncpyz(ent.filename, (char *)hl.hlname, hl.name_len + 1); - ent.lastmodified_time = amiga_crack_time(&hl.date); - amiga_decode_flags(hl.protect, ent.attr); - strncpyz(ent.comment, (char *)hl.comment, hl.comm_len + 1); - ent.hardlink = 1; - - iter->next_block = hl.hash_chain; - - break; - } - - default: - return IMGTOOLERR_UNIMPLEMENTED; - } - - /* if there are no linked entries, go to the next hash table entry */ - if (iter->next_block == 0) - { - iter->ht_index++; - } - - /* jump to next index */ - iter->index++; - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t amiga_image_freespace(imgtool::partition &partition, uint64_t *size) -{ - imgtoolerr_t ret; - imgtool::image &image(partition.image()); - const int data_size = is_ffs(image) ? BSIZE : BSIZE-24; - root_block root; - bitmap_block bm; - int blocks, blocks_processed = 0, pages, i, c; - uint32_t v; - - /* initialize size */ - *size = 0; - - /* get root block */ - ret = read_root_block(image, &root); - if (ret) return ret; - - /* get total number of blocks in the image */ - blocks = get_total_blocks(image); - - /* subtract the two bootblock blocks (only for floppies!) */ - blocks -= 2; - - /* iterate all bitmap pages */ - for (pages = 0; pages < 25; pages++) - { - ret = read_bitmap_block(image, root.bm_pages[pages], &bm); - if (ret) return ret; - - for (i = 0; i < MSIZE; i++) - { - v = bm.map[i]; - - /* clear half used value */ - if ((blocks_processed + 32) > blocks) - v &= ~(~0 << (blocks - blocks_processed)); - - /* count bits */ - for (c = 0; v; c++) - v &= v - 1; - - *size += c * data_size; - - blocks_processed += 32; - - if (blocks_processed >= blocks) - return IMGTOOLERR_SUCCESS; - } - } - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t amiga_image_readfile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &destf) -{ - imgtool::image &img(partition.image()); - imgtoolerr_t ret; - file_block file; - int filesize, block; - - /* Search for the block number */ - ret = find_entry(img, filename, get_total_blocks(img)/2, &block); - if (ret == IMGTOOLERR_PATHNOTFOUND) return IMGTOOLERR_FILENOTFOUND; - if (ret) return ret; /* Other errors */ - - /* Phase 1: Follow data pointers */ - ret = read_file_block(img, block, &file); - if (ret) return ret; - - filesize = file.byte_size; - - /* Write out file data pointed to by data block pointers */ - ret = write_data_block_ptr(img, file.data_blocks, &filesize, destf); - if (ret) return ret; - - /* Check if we are done already */ - if (filesize == 0) return IMGTOOLERR_SUCCESS; - - /* Phase 2: Follow file extension blocks */ - ret = write_file_ext_data(img, file.extension, &filesize, &destf); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - - -/* When a file is deleted, only its File header block number is cleared from - * the Directory block (or from the same-hash-value list) and the bitmap is - * updated. File header block, Data blocks and File extension blocks are not - * cleared, but the bitmap blocks are updated. */ -static imgtoolerr_t amiga_image_deletefile(imgtool::partition &partition, const char *fname) -{ - imgtool::image &img(partition.image()); - imgtoolerr_t ret; - int parent, block; - char filename[31]; - - /* Initialize filename */ - memset(filename, 0, sizeof(filename)); - - /* Search for the block number */ - ret = find_entry(img, fname, get_total_blocks(img)/2, &block); - if (ret == IMGTOOLERR_PATHNOTFOUND) return IMGTOOLERR_FILENOTFOUND; - if (ret) return ret; - - /* Get the parent block, where we need to clear the hash */ - switch (get_block_type(img, block)) - { - case ST_FILE: - { - file_block file; - int filesize; - - ret = read_file_block(img, block, &file); - if (ret) return ret; - - filesize = file.byte_size; - parent = file.parent; - memcpy(filename, file.filename, file.name_len); - - /* Clear all linked data sectors */ - ret = clear_data_block_ptr(img, file.data_blocks, &filesize); - if (ret) return ret; - - /* Clear extended file data sectors */ - if (filesize != 0) - { - ret = clear_file_ext_data(img, file.extension, &filesize); - if (ret) return ret; - } - - break; - } - - case ST_LINKFILE: - { - softlink_block link; - - ret = read_softlink_block(img, block, &link); - if (ret) return ret; - - parent = link.parent; - memcpy(filename, link.slname, link.name_len); - - break; - } - - default: - return IMGTOOLERR_UNEXPECTED; - } - - /* Clear hash table entry */ - ret = clear_hash_table_entry(img, parent, filename); - if (ret) return ret; - - /* Update disk alteration date */ - ret = update_disk_alteration_date(img); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t amiga_image_writefile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &sourcef, util::option_resolution *opts) -{ - return IMGTOOLERR_UNIMPLEMENTED; -} - - -static imgtoolerr_t amiga_image_create(imgtool::image &img, imgtool::stream::ptr &&stream, util::option_resolution *opts) -{ - amiga_floppy *f = get_amiga_floppy(img); - const std::string &dskname = opts->lookup_string('N'); - imgtoolerr_t ret; - uint8_t buffer[BSIZE]; - root_block root; - bitmap_block bm; - time_t now; - int blocks; - - f->stream = stream.get(); - - switch (opts->lookup_int('S')) - { - case 0: f->sectors = 11; break; - case 1: f->sectors = 22; break; - default: return IMGTOOLERR_PARAMCORRUPT; - } - - /* initialize with zeros */ - memset(buffer, 0, BSIZE); - - /* add DOS magic string and flags */ - buffer[0] = 'D'; - buffer[1] = 'O'; - buffer[2] = 'S'; - buffer[3] = 0; - - /* File system */ - buffer[3] += (opts->lookup_int('F')); - - /* File system mode */ - buffer[3] += (opts->lookup_int('M')); - - /* write first bootblock sector */ - ret = write_block(img, 0, buffer); - if (ret) return ret; - - /* reset with zeros */ - memset(buffer, 0, BSIZE); - - /* write second bootblock sector */ - ret = write_block(img, 1, buffer); - if (ret) return ret; - - /* rootblock */ - memset(&root, 0, sizeof(root_block)); - - blocks = get_total_blocks(img); - - root.chksum = 0; - root.ht_size = TSIZE; - root.bm_flag = -1; - root.bm_pages[0] = blocks/2 + 1; /* generally it's located here */ - - time(&now); - amiga_setup_time(now, &root.r); - amiga_setup_time(now, &root.v); - amiga_setup_time(now, &root.c); - - /* volume name */ - if (!dskname.empty()) - { - root.name_len = dskname.length(); - memcpy(&root.diskname, dskname.c_str(), root.name_len); - } - else - { - root.name_len = strlen("Empty"); - memcpy(&root.diskname, "Empty", root.name_len); - } - - /* write root block to disk */ - ret = write_root_block(img, &root); - if (ret) return ret; - - /* calculate block checksum */ - ret = fix_block_chksum(img, blocks/2); - if (ret) return ret; - - /* bitmap block */ - memset(&bm, 0xff, sizeof(bitmap_block)); - - /* write bitmap block to disk */ - ret = write_bitmap_block(img, root.bm_pages[0], &bm); - if (ret) return ret; - - /* set root and bitmap block as used */ - ret = bitmap_mark_used(img, blocks/2); - if (ret) return ret; - - ret = bitmap_mark_used(img, root.bm_pages[0]); - if (ret) return ret; - - /* write empty last block so that we don't get a truncated image */ - memset(buffer, 0, BSIZE); - - ret = write_block(img, blocks - 1, buffer); - if (ret) return ret; - - f->stream = stream.release(); - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t amiga_image_createdir(imgtool::partition &partition, const char *path) -{ - imgtool::image &img(partition.image()); - imgtoolerr_t ret; - - /* Create directories */ - ret = checkdir(img, path, get_total_blocks(img)/2); - if (ret) return ret; - - /* Update disk alteration date */ - ret = update_disk_alteration_date(img); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t amiga_image_getattrs(imgtool::partition &partition, const char *path, const uint32_t *attrs, imgtool_attribute *values) -{ - return IMGTOOLERR_UNIMPLEMENTED; -} - - -static imgtoolerr_t amiga_image_setattrs(imgtool::partition &partition, const char *path, const uint32_t *attrs, const imgtool_attribute *values) -{ - return IMGTOOLERR_UNIMPLEMENTED; -} - - -static imgtoolerr_t amiga_image_geticoninfo(imgtool::partition &partition, const char *path, imgtool_iconinfo *iconinfo) -{ - return IMGTOOLERR_UNIMPLEMENTED; -} - - -static imgtoolerr_t amiga_image_suggesttransfer(imgtool::partition &partition, const char *fname, imgtool_transfer_suggestion *suggestions, size_t suggestions_length) -{ - return IMGTOOLERR_UNIMPLEMENTED; -} - - - -/***************************************************************************** - Create image options -*****************************************************************************/ - - -OPTION_GUIDE_START(amiga_createimage_optionguide) - OPTION_STRING( 'N', "name", "Volume name" ) - OPTION_ENUM_START( 'S', "density", "Density" ) - OPTION_ENUM( 0, "dd", "Double Density" ) - OPTION_ENUM( 1, "hd", "High Density" ) - OPTION_ENUM_END - OPTION_ENUM_START( 'F', "filesystem", "File system" ) - OPTION_ENUM( 0, "ofs", "OldFileSystem" ) - OPTION_ENUM( 1, "ffs", "FastFileSystem" ) - OPTION_ENUM_END - OPTION_ENUM_START( 'M', "mode", "File system options" ) - OPTION_ENUM( 0, "none", "None" ) - OPTION_ENUM( 2, "intl", "International Mode" ) - OPTION_ENUM( 4, "dirc", "International Mode with Directory Cache" ) - OPTION_ENUM_END -OPTION_GUIDE_END - - - -/***************************************************************************** - Imgtool module declaration -*****************************************************************************/ - - -/* Amiga floppy disk attributes */ -void amiga_floppy_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_IMAGE_EXTRA_BYTES: info->i = sizeof(amiga_floppy); break; - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(amiga_iterator); break; - 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 --- */ - 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; - case IMGTOOLINFO_STR_FILE: strcpy(info->s = imgtool_temp_str(), __FILE__); break; - case IMGTOOLINFO_STR_EOLN: strcpy(info->s = imgtool_temp_str(), EOLN_LF); break; - case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC: strcpy(info->s = imgtool_temp_str(), "S[0]-1;F[0]-1;M[0]/2/4"); break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case IMGTOOLINFO_PTR_OPEN: info->open = amiga_image_open; break; - case IMGTOOLINFO_PTR_CLOSE: info->close = amiga_image_exit; break; - case IMGTOOLINFO_PTR_READ_SECTOR: info->read_sector = amiga_image_read_sector; break; - case IMGTOOLINFO_PTR_WRITE_SECTOR: info->write_sector = amiga_image_write_sector; break; - case IMGTOOLINFO_PTR_CREATE: info->create = amiga_image_create; break; - case IMGTOOLINFO_PTR_INFO: info->info = amiga_image_info; break; - case IMGTOOLINFO_PTR_BEGIN_ENUM: info->begin_enum = amiga_image_beginenum; break; - case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = amiga_image_nextenum; break; - case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = amiga_image_freespace; break; - case IMGTOOLINFO_PTR_READ_FILE: info->read_file = amiga_image_readfile; break; - case IMGTOOLINFO_PTR_WRITE_FILE: info->write_file = amiga_image_writefile; break; - case IMGTOOLINFO_PTR_DELETE_FILE: info->delete_file = amiga_image_deletefile; break; - case IMGTOOLINFO_PTR_CREATE_DIR: info->create_dir = amiga_image_createdir; break; - case IMGTOOLINFO_PTR_GET_ATTRS: info->get_attrs = amiga_image_getattrs; break; - case IMGTOOLINFO_PTR_SET_ATTRS: info->set_attrs = amiga_image_setattrs; break; - case IMGTOOLINFO_PTR_GET_ICON_INFO: info->get_iconinfo = amiga_image_geticoninfo; break; - case IMGTOOLINFO_PTR_SUGGEST_TRANSFER: info->suggest_transfer = amiga_image_suggesttransfer; break; - case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE: info->createimage_optguide = &amiga_createimage_optionguide; break; - case IMGTOOLINFO_PTR_CHARCONVERTER: info->charconverter = &imgtool::charconverter_iso_8859_1; break; - } -} diff --git a/src/tools/imgtool/modules/bml3.cpp b/src/tools/imgtool/modules/bml3.cpp deleted file mode 100644 index ecb33c0..0000000 --- a/src/tools/imgtool/modules/bml3.cpp +++ /dev/null @@ -1,932 +0,0 @@ -// license:GPL-2.0+ -// copyright-holders:Jonathan Edwards -/**************************************************************************** - - bml3.c - - Hitachi bml3 disk images - - By Jonathan Edwards, based on rsdos.c (both use Microsoft BASIC) - -****************************************************************************/ - -/* Supported Hitachi floppy formats are: - - 3" or 5"1/4 single density, single-sided: 40 tracks, 16 sectors/track, 128 bytes/sector - - (used with MP-1805 floppy disk controller card) - - 5"1/4 double density, double-sided: 40 tracks, 16 sectors/track, 256 bytes/sector - - (first track on first head may be single density) - - (used with MP-1802 floppy disk controller card) -*/ - -#include "imgtool.h" -#include "filter.h" -#include "iflopimg.h" - -#include "corestr.h" -#include "opresolv.h" - -#include -#include -#include - -#define MAX_SECTOR_SIZE 256 - -struct bml3_diskinfo -{ - uint16_t sector_size; /* 128 or 256 */ - uint8_t heads; /* 1 or 2 */ - uint8_t fat_start_sector; /* in cylinder 20, start sector of FAT */ - uint8_t fat_start_offset; /* start byte of FAT in sector */ - uint8_t fat_sectors; /* the number of sectors in the FAT */ - uint8_t dirent_start_sector; /* in cylinder 20, start sector of directory entries */ - uint8_t granule_sectors; /* how many sectors per granule */ - uint8_t first_granule_cylinder; /* the number of the first cylinder with granule numbers assigned */ - uint8_t variant; /* 0 - older version, uses EOF to terminate files, 1 - newer version, stores file length */ -}; - -/* this structure mirrors the structure of a directory entry on disk */ -struct bml3_dirent -{ - char fname[8]; - char fext[3]; - uint8_t ftype; - uint8_t asciiflag; - uint8_t first_granule; - uint16_t lastsectorbytes; - // TODO there are some 'unused' bytes here that are sometimes used to store a timestamp, maybe support this? -}; - -struct bml3_direnum -{ - int index; - int eof; -}; - -#define MAX_GRANULEMAP_SIZE 256 - -struct granule_list_t { - uint8_t granules[MAX_GRANULEMAP_SIZE]; - uint8_t granule_count; - uint8_t last_granule_sectors; -}; - -#define BML3_OPTIONS_FTYPE 'T' -#define BML3_OPTIONS_ASCII 'M' - -static imgtoolerr_t bml3_diskimage_deletefile(imgtool::partition &partition, const char *fname); - - - -/********************************************************************* - Imgtool module code -*********************************************************************/ - -static bml3_diskinfo *bml3_get_diskinfo(imgtool::image &image) -{ - return (bml3_diskinfo *) imgtool_floppy_extrabytes(image); -} - - - -static int max_dirents(imgtool::image &image) -{ - bml3_diskinfo *info = bml3_get_diskinfo(image); - return (16 * info->heads + 1 - info->dirent_start_sector)*(info->sector_size/32); -} - - - -static void dirent_location(imgtool::image &image, int index_loc, uint8_t *head, uint8_t *track, uint8_t *sector, uint8_t *offset) -{ - bml3_diskinfo *info = bml3_get_diskinfo(image); - *track = 20; - *sector = info->dirent_start_sector + index_loc / (info->sector_size / 32); - *head = 0; - if (*sector > 16) { - // wrap to second head - *sector -= 16; - (*head)++; - } - *offset = index_loc % (info->sector_size/32) * 32; -} - - - -static floperr_t get_bml3_dirent(imgtool::image &f, int index_loc, struct bml3_dirent *ent) -{ - floperr_t err; - uint8_t head, track, sector, offset; - uint8_t buf[32]; - bml3_diskinfo *info = bml3_get_diskinfo(f); - dirent_location(f, index_loc, &head, &track, §or, &offset); - err = floppy_read_sector(imgtool_floppy(f), head, track, sector, offset, (void *) buf, sizeof(buf)); - memset(ent, 0, sizeof(*ent)); - switch (info->variant) { - case 0: - memcpy(&ent->fname, &buf[0], 8); - ent->ftype = buf[11]; - ent->asciiflag = buf[12]; - ent->first_granule = buf[14]; - break; - case 1: - memcpy(&ent->fname, &buf[0], 8); - memcpy(&ent->fext, &buf[8], 3); - ent->ftype = buf[11]; - ent->asciiflag = buf[12]; - ent->first_granule = buf[13]; - ent->lastsectorbytes = (buf[14] << 8) | buf[15]; - break; - default: - return FLOPPY_ERROR_INVALIDIMAGE; - } - return err; -} - - - -static floperr_t put_bml3_dirent(imgtool::image &f, int index_loc, const struct bml3_dirent *ent) -{ - floperr_t err; - uint8_t head, track, sector, offset; - uint8_t buf[32]; - bml3_diskinfo *info = bml3_get_diskinfo(f); - if (index_loc >= max_dirents(f)) - return (floperr_t)IMGTOOLERR_FILENOTFOUND; - dirent_location(f, index_loc, &head, &track, §or, &offset); - memset(buf, 0, sizeof(buf)); - switch (info->variant) { - case 0: - memcpy(&buf[0], &ent->fname, 8); - buf[11] = ent->ftype; - buf[12] = ent->asciiflag; - buf[14] = ent->first_granule; - break; - case 1: - memcpy(&buf[0], &ent->fname, 8); - memcpy(&buf[8], &ent->fext, 3); - buf[11] = ent->ftype; - buf[12] = ent->asciiflag; - buf[13] = ent->first_granule; - buf[14] = ent->lastsectorbytes >> 8; - buf[15] = ent->lastsectorbytes & 0xff; - break; - default: - return FLOPPY_ERROR_INVALIDIMAGE; - } - err = floppy_write_sector(imgtool_floppy(f), head, track, sector, offset, (void *) buf, sizeof(buf), 0); /* TODO: pass ddam argument from imgtool */ - return err; -} - - - -/* fnamebuf must have at least 13 bytes */ -static void get_dirent_fname(char *fnamebuf, const struct bml3_dirent *ent) -{ - char *s; - - memset(fnamebuf, 0, 13); - memcpy(fnamebuf, ent->fname, sizeof(ent->fname)); - rtrim(fnamebuf); - s = fnamebuf + strlen(fnamebuf); - *(s++) = '.'; - memcpy(s, ent->fext, sizeof(ent->fext)); - rtrim(s); - - /* If no extension, remove period */ - if (*s == '\0') - s[-1] = '\0'; -} - - - -static imgtoolerr_t lookup_bml3_file(imgtool::image &f, const char *fname, struct bml3_dirent *ent, int *position) -{ - int i; - floperr_t ferr; - char fnamebuf[13]; - - i = 0; - fnamebuf[0] = '\0'; - - do - { - do - { - ferr = get_bml3_dirent(f, i++, ent); - if (ferr) - return imgtool_floppy_error(ferr); - } - while(ent->fname[0] == '\0'); - - - if (ent->fname[0] != -1) - get_dirent_fname(fnamebuf, ent); - } - while((ent->fname[0] != -1) && core_stricmp(fnamebuf, fname)); - - if (ent->fname[0] == -1) - return IMGTOOLERR_FILENOTFOUND; - - if (position) - *position = i - 1; - return (imgtoolerr_t)0; -} - - - -static uint8_t get_granule_count(imgtool::image &img) -{ - // uint16_t tracks; - uint16_t disk_granules; - bml3_diskinfo *info = bml3_get_diskinfo(img); - - // This always returns 82 for D88, so not quite right - // tracks = floppy_get_tracks_per_disk(imgtool_floppy(img)); - - // The number of granules is primarily constrained by the disk capacity. - disk_granules = (40 - 1 - info->first_granule_cylinder) * info->heads * (16 / info->granule_sectors); - // Also, granule numbers from 0xC0 upwards are reserved for terminating a granule chain - return (uint8_t)((disk_granules < 0xC0) ? disk_granules : 0xC0); -} - -/* granule_map must be an array of MAX_GRANULEMAP_SIZE bytes */ -static floperr_t get_granule_map(imgtool::image &img, uint8_t *granule_map, uint8_t *granule_count) -{ - bml3_diskinfo *info = bml3_get_diskinfo(img); - uint8_t count; - - count = get_granule_count(img); - if (granule_count) - *granule_count = count; - - // The first byte of the granule map sector is ignored (and expected to be 0) - return floppy_read_sector(imgtool_floppy(img), 0, 20, info->fat_start_sector, info->fat_start_offset, granule_map, count); -} - - - -static floperr_t put_granule_map(imgtool::image &img, const uint8_t *granule_map, uint8_t granule_count) -{ - bml3_diskinfo *info = bml3_get_diskinfo(img); - return floppy_write_sector(imgtool_floppy(img), 0, 20, info->fat_start_sector, info->fat_start_offset, granule_map, granule_count, 0); /* TODO: pass ddam argument from imgtool */ -} - - - - -static void granule_location(imgtool::image &image, uint8_t granule, uint8_t *head, uint8_t *track, uint8_t *sector) -{ - bml3_diskinfo *info = bml3_get_diskinfo(image); - uint16_t abs_track = granule * info->granule_sectors / 16; - *head = abs_track % info->heads; - *track = abs_track / info->heads + info->first_granule_cylinder; - // skip filesystem cylinder - if (*track >= 20) - (*track)++; - *sector = granule * info->granule_sectors % 16 + 1; -} - - - -static imgtoolerr_t transfer_granule(imgtool::image &img, uint8_t granule, int length, imgtool::stream &f, imgtoolerr_t (*proc)(imgtool::image &, int, int, int, int, size_t, imgtool::stream &)) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - uint8_t head, track, sector; - granule_location(img, granule, &head, &track, §or); - if (length > 0) - err = proc(img, head, track, sector, 0, length, f); - return err; -} - - -static imgtoolerr_t transfer_from_granule(imgtool::image &img, uint8_t granule, int length, imgtool::stream &destf) -{ - return transfer_granule(img, granule, length, destf, imgtool_floppy_read_sector_to_stream); -} - - - -static imgtoolerr_t transfer_to_granule(imgtool::image &img, uint8_t granule, int length, imgtool::stream &sourcef) -{ - return transfer_granule(img, granule, length, sourcef, imgtool_floppy_write_sector_from_stream); -} - - - -static floperr_t read_granule(imgtool::image &img, uint8_t granule, int offset, int length, uint8_t *buf) -{ - uint8_t head, track, sector; - granule_location(img, granule, &head, &track, §or); - return floppy_read_sector(imgtool_floppy(img), head, track, sector, offset, buf, length); -} - - - -static floperr_t write_granule(imgtool::image &img, uint8_t granule, int offset, int length, const uint8_t *buf) -{ - uint8_t head, track, sector; - granule_location(img, granule, &head, &track, §or); - return floppy_write_sector(imgtool_floppy(img), head, track, sector, offset, buf, length, 0); /* TODO: pass ddam argument from imgtool */ -} - - - -static imgtoolerr_t list_granules(struct bml3_dirent *ent, imgtool::image &img, struct granule_list_t *granule_list) -{ - floperr_t ferr; - uint8_t max_granules; - uint8_t granule; - uint8_t usedmap[MAX_GRANULEMAP_SIZE]; /* Used to detect infinite loops */ - uint8_t granule_map[MAX_GRANULEMAP_SIZE]; - bml3_diskinfo *info = bml3_get_diskinfo(img); - - ferr = get_granule_map(img, granule_map, &max_granules); - if (ferr) - return imgtool_floppy_error(ferr); - - memset(usedmap, 0, max_granules); - - granule = ent->first_granule; - granule_list->granule_count = 0; - - while(!usedmap[granule] && granule < max_granules) - { - usedmap[granule] = 1; - granule_list->granules[granule_list->granule_count++] = granule; - granule = granule_map[granule]; - } - - granule_list->last_granule_sectors = granule - 0xc0; - if (info->variant == 0) { - // add final incomplete sector - granule_list->last_granule_sectors++; - } - - // A value of zero (variant 1) and max (variant 0) seem to indicate a file open for writing. - // Strictly speaking this means the image is corrupt, although a real system will happily read - // garbage from the file. - if (granule_list->last_granule_sectors > info->granule_sectors) - return IMGTOOLERR_CORRUPTIMAGE; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t get_file_size(struct bml3_dirent *ent, imgtool::image &img, const struct granule_list_t *granule_list, size_t *size) -{ - floperr_t ferr; - size_t last_sector_bytes = 0; - bml3_diskinfo *info = bml3_get_diskinfo(img); - - // TODO are these special cases valid, or maybe indicate a corrupt image? - if (granule_list->granule_count == 0) { - *size = 0; - return IMGTOOLERR_SUCCESS; - } - else if (granule_list->last_granule_sectors == 0) { - *size = info->sector_size * ((granule_list->granule_count - 1) * info->granule_sectors); - return IMGTOOLERR_SUCCESS; - } - - // determine size excluding final sector - *size = info->sector_size * ((granule_list->granule_count - 1) * info->granule_sectors + granule_list->last_granule_sectors - 1); - - // determine bytes used in final sector - switch (info->variant) { - case 0: - // look for EOF (ASCII SUB) and trailing NULs in final sector - { - uint8_t buf[MAX_SECTOR_SIZE]; - ferr = read_granule(img, granule_list->granules[granule_list->granule_count-1], info->sector_size * (granule_list->last_granule_sectors - 1), info->sector_size, buf); - if (ferr) - return imgtool_floppy_error(ferr); - for (last_sector_bytes = info->sector_size - 1; ; last_sector_bytes--) { - if (buf[last_sector_bytes] != 0) - break; - if (last_sector_bytes == 0) - break; - } - if (buf[last_sector_bytes] != 0x1a) { - last_sector_bytes++; - } - } - break; - case 1: - last_sector_bytes = ent->lastsectorbytes; - break; - } - - // TODO is it valid for last_sector_bytes == 0? - if (last_sector_bytes > info->sector_size) { - return IMGTOOLERR_CORRUPTIMAGE; - } - *size += last_sector_bytes; - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t process_bml3_file(struct bml3_dirent *ent, imgtool::image &img, imgtool::stream *destf, size_t *size) -{ - imgtoolerr_t err; - size_t remaining_size, granule_size; - bml3_diskinfo *info = bml3_get_diskinfo(img); - struct granule_list_t granule_list; - granule_list.granule_count = 0; - - err = list_granules(ent, img, &granule_list); - if (err) - return err; - err = get_file_size(ent, img, &granule_list, size); - if (err) - return err; - - if (destf) { - remaining_size = *size; - granule_size = info->granule_sectors * info->sector_size; - - for (int c = 0; c < granule_list.granule_count; c++) { - if (granule_size >= remaining_size) - granule_size = remaining_size; - transfer_from_granule(img, granule_list.granules[c], granule_size, *destf); - remaining_size -= granule_size; - } - } - return IMGTOOLERR_SUCCESS; -} - - - -/* create a new directory entry with a specified name */ -static imgtoolerr_t prepare_dirent(uint8_t variant, struct bml3_dirent *ent, const char *fname) -{ - const char *fname_end; - const char *fname_ext; - int fname_ext_len; - - memset(ent, '\0', sizeof(*ent)); - memset(ent->fname, ' ', sizeof(ent->fname)); - memset(ent->fext, ' ', sizeof(ent->fext)); - - 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); - - switch (variant) { - case 0: - /* 8-character max filename */ - if (((fname_end - fname) > 8) || (fname_ext_len > 0)) - return IMGTOOLERR_BADFILENAME; - break; - case 1: - /*8.3 filename */ - if (((fname_end - fname) > 8) || (fname_ext_len > 3)) - return IMGTOOLERR_BADFILENAME; - break; - default: - return IMGTOOLERR_CORRUPTIMAGE; - } - - memcpy(ent->fname, fname, fname_end - fname); - memcpy(ent->fext, fname_ext, fname_ext_len); - - /* By default, set as a type 2 binary file */ - ent->ftype = 2; - ent->asciiflag = 0; - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t bml3_diskimage_open(imgtool::image &image, imgtool::stream::ptr &&dummy) -{ - // imgtoolerr_t err; - floperr_t ferr; - bml3_diskinfo *info = bml3_get_diskinfo(image); - floppy_image_legacy *floppy = imgtool_floppy(image); - const struct FloppyCallbacks *callbacks = floppy_callbacks(floppy); - - // probe disk geometry to guess format - int heads_per_disk = callbacks->get_heads_per_disk(floppy); - uint32_t sector_length; - 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); - - if (heads_per_disk == 2 && sector_length == 128 && sectors_per_track == 16) { - // single-sided, single-density - info->sector_size = 128; - info->heads = 1; - info->fat_start_sector = 1; - info->fat_start_offset = 5; - info->fat_sectors = 2; - info->dirent_start_sector = 7; - info->granule_sectors = 4; - info->first_granule_cylinder = 0; - info->variant = 0; - } - else if (heads_per_disk == 2 && sector_length == 256 && sectors_per_track == 16) { - // double-sided, double-density - info->sector_size = 256; - info->heads = 2; - info->fat_start_sector = 2; - info->fat_start_offset = 1; - info->fat_sectors = 1; - info->dirent_start_sector = 5; - info->granule_sectors = 8; - info->first_granule_cylinder = 1; - info->variant = 1; - } - else { - // invalid or unsupported format - return IMGTOOLERR_CORRUPTIMAGE; - } - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t bml3_diskimage_nextenum(imgtool::directory &enumeration, imgtool_dirent &ent) -{ - floperr_t ferr; - imgtoolerr_t err; - size_t filesize; - struct bml3_direnum *rsenum; - struct bml3_dirent rsent; - char fname[13]; - imgtool::image &image(enumeration.image()); - - rsenum = (struct bml3_direnum *) enumeration.extra_bytes(); - - /* Did we hit the end of file before? */ - if (rsenum->eof) - goto eof; - - do - { - if (rsenum->index >= max_dirents(image)) - goto eof; - - ferr = get_bml3_dirent(image, rsenum->index++, &rsent); - if (ferr) - return imgtool_floppy_error(ferr); - } - while(rsent.fname[0] == '\0'); - - /* Now are we at the eof point? */ - if (rsent.fname[0] == -1) - { - rsenum->eof = 1; -eof: - ent.eof = 1; - } - else - { - /* Not the end of file */ - err = process_bml3_file(&rsent, image, nullptr, &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; - - get_dirent_fname(fname, &rsent); - - 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; -} - - - -static imgtoolerr_t bml3_diskimage_freespace(imgtool::partition &partition, uint64_t *size) -{ - floperr_t ferr; - uint8_t i; - size_t s = 0; - uint8_t granule_count; - uint8_t granule_map[MAX_GRANULEMAP_SIZE]; - imgtool::image &image(partition.image()); - bml3_diskinfo *info = bml3_get_diskinfo(image); - - ferr = get_granule_map(image, granule_map, &granule_count); - if (ferr) - return imgtool_floppy_error(ferr); - - for (i = 0; i < granule_count; i++) - { - if (granule_map[i] == 0xff) - s += (info->granule_sectors * info->sector_size); - } - *size = s; - return (imgtoolerr_t)FLOPPY_ERROR_SUCCESS; -} - - - -static imgtoolerr_t delete_entry(imgtool::image &img, struct bml3_dirent *ent, int pos) -{ - floperr_t ferr; - unsigned char g, i; - uint8_t granule_count; - uint8_t granule_map[MAX_GRANULEMAP_SIZE]; - - /* Write a NUL in the filename, marking it deleted */ - ent->fname[0] = 0; - ferr = put_bml3_dirent(img, pos, ent); - if (ferr) - return imgtool_floppy_error(ferr); - - ferr = get_granule_map(img, granule_map, &granule_count); - if (ferr) - return imgtool_floppy_error(ferr); - - /* Now free up the granules */ - g = ent->first_granule; - while (g < granule_count) - { - i = granule_map[g]; - granule_map[g] = 0xff; - g = i; - } - - ferr = put_granule_map(img, granule_map, granule_count); - if (ferr) - return imgtool_floppy_error(ferr); - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t bml3_diskimage_readfile(imgtool::partition &partition, const char *fname, const char *fork, imgtool::stream &destf) -{ - imgtoolerr_t err; - struct bml3_dirent ent; - size_t size; - imgtool::image &img(partition.image()); - - err = lookup_bml3_file(img, fname, &ent, nullptr); - if (err) - return err; - - err = process_bml3_file(&ent, img, &destf, &size); - if (err) - return err; - - if (size == (size_t) -1) - return IMGTOOLERR_CORRUPTIMAGE; - - return (imgtoolerr_t)0; -} - - - -static imgtoolerr_t bml3_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 &img(partition.image()); - bml3_diskinfo *info = bml3_get_diskinfo(img); - struct bml3_dirent ent, ent2; - size_t i; - uint64_t sz, read_sz; - uint64_t freespace = 0; - unsigned char *gptr; - uint8_t granule_count; - uint8_t granule_map[MAX_GRANULEMAP_SIZE]; - uint8_t eof_buf[MAX_SECTOR_SIZE]; - - // one-time setup of eof_buf - memset(eof_buf, 0, sizeof(eof_buf)); - eof_buf[0] = 0x1A; - - /* can we write to this image? */ - if (floppy_is_read_only(imgtool_floppy(img))) - return IMGTOOLERR_READONLY; - - err = bml3_diskimage_freespace(partition, &freespace); - if (err) - return err; - - /* is there enough space? */ - sz = read_sz = sourcef.size(); - if (info->variant == 0) { - // also need to write EOF - sz++; - } - if (sz > freespace) - return IMGTOOLERR_NOSPACE; - - /* setup our directory entry */ - err = prepare_dirent(info->variant, &ent, fname); - if (err) - return err; - - ent.ftype = writeoptions->lookup_int(BML3_OPTIONS_FTYPE); - ent.asciiflag = uint8_t(writeoptions->lookup_int(BML3_OPTIONS_ASCII)) - 1; - gptr = &ent.first_granule; - - ferr = get_granule_map(img, granule_map, &granule_count); - if (ferr) - return imgtool_floppy_error(ferr); - - unsigned char g = 0x00; - uint32_t granule_bytes = info->granule_sectors * info->sector_size; - - do - { - while (granule_map[g] != 0xff) - { - g++; - if ((g >= granule_count) || (g == 0)) - return IMGTOOLERR_UNEXPECTED; /* We should have already verified that there is enough space */ - } - *gptr = g; - gptr = &granule_map[g]; - - - i = std::min(read_sz, uint64_t(granule_bytes)); - if (i > 0) { - err = transfer_to_granule(img, g, i, sourcef); - if (err) - return err; - read_sz -= i; - sz -= i; - } - if (i < info->granule_sectors * info->sector_size && sz > 0) { - // write EOF and trailing NULs in the final sector - ferr = write_granule(img, g, i, (info->granule_sectors * info->sector_size - i - 1) % info->sector_size + 1, eof_buf); - if (ferr) - return imgtool_floppy_error(ferr); - sz--; - i++; - } - - /* Go to next granule */ - g++; - } - while(sz > 0); - - /* Now that we are done with the file, we need to specify the final entry - * in the file allocation table - */ - *gptr = 0xc0 + ((i + info->sector_size-1) / info->sector_size) - (info->variant == 0 ? 1 : 0); - ent.lastsectorbytes = (i - 1) % info->sector_size + 1; - - /* delete file if it already exists */ - err = bml3_diskimage_deletefile(partition, fname); - if (err && err != IMGTOOLERR_FILENOTFOUND) - return err; - - /* Now we need to find an empty directory entry */ - i = -1; - do - { - ferr = get_bml3_dirent(img, ++i, &ent2); - if (ferr) - return imgtool_floppy_error(ferr); - } - while(ent2.fname[0] != '\0' && ent2.fname[0] != -1); - - ferr = put_bml3_dirent(img, i, &ent); - if (ferr) - return imgtool_floppy_error(ferr); - - /* write the granule map back out */ - ferr = put_granule_map(img, granule_map, granule_count); - if (ferr) - return imgtool_floppy_error(ferr); - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t bml3_diskimage_deletefile(imgtool::partition &partition, const char *fname) -{ - imgtoolerr_t err; - imgtool::image &image(partition.image()); - int pos = 0; - struct bml3_dirent ent; - - err = lookup_bml3_file(image, fname, &ent, &pos); - if (err) - return err; - - return delete_entry(image, &ent, pos); -} - - - -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()); - struct bml3_dirent ent; - int pos; - - if (fname) - { - err = lookup_bml3_file(image, fname, &ent, &pos); - if (err) - return err; - - if (ent.asciiflag == 0xFF) - { - /* ASCII file */ - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = filter_eoln_getinfo; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = NULL; - } - else if (ent.ftype == 0) - { - /* tokenized BASIC file */ - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = filter_bml3bas_getinfo; - } - } - else - { - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = filter_eoln_getinfo; - suggestions[2].viability = SUGGESTION_POSSIBLE; - suggestions[2].filter = filter_bml3bas_getinfo; - } - - return IMGTOOLERR_SUCCESS; -} - - - -/********************************************************************* - Imgtool module declaration -*********************************************************************/ - -OPTION_GUIDE_START( bml3_writefile_optionguide ) - OPTION_ENUM_START( BML3_OPTIONS_FTYPE, "ftype", "File type" ) - OPTION_ENUM( 0, "basic", "Basic" ) - OPTION_ENUM( 1, "data", "Data" ) - OPTION_ENUM( 2, "binary", "Binary" ) - OPTION_ENUM( 3, "assembler", "Assembler Source" ) - OPTION_ENUM_END - OPTION_ENUM_START( BML3_OPTIONS_ASCII, "ascii", "Ascii flag" ) - OPTION_ENUM( 0, "ascii", "Ascii" ) - OPTION_ENUM( 1, "binary", "Binary" ) - OPTION_ENUM_END -OPTION_GUIDE_END - - - -void bml3_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_IMAGE_EXTRA_BYTES: info->i = sizeof(bml3_diskinfo); 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 --- */ - 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; - case IMGTOOLINFO_STR_EOLN: strcpy(info->s = imgtool_temp_str(), "\r"); break; - case IMGTOOLINFO_STR_WRITEFILE_OPTSPEC: strcpy(info->s = imgtool_temp_str(), "T0-[2]-3;M0-[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_OPEN: info->open = bml3_diskimage_open; break; - case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = bml3_diskimage_nextenum; break; - case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = bml3_diskimage_freespace; break; - case IMGTOOLINFO_PTR_READ_FILE: info->read_file = bml3_diskimage_readfile; break; - case IMGTOOLINFO_PTR_WRITE_FILE: info->write_file = bml3_diskimage_writefile; break; - case IMGTOOLINFO_PTR_DELETE_FILE: info->delete_file = bml3_diskimage_deletefile; break; - case IMGTOOLINFO_PTR_SUGGEST_TRANSFER: info->suggest_transfer = bml3_diskimage_suggesttransfer; break; - case IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE: info->writefile_optguide = &bml3_writefile_optionguide; break; - case IMGTOOLINFO_PTR_FLOPPY_FORMAT: info->p = (void *) floppyoptions_default; break; - } -} diff --git a/src/tools/imgtool/modules/concept.cpp b/src/tools/imgtool/modules/concept.cpp deleted file mode 100644 index 7bfa7b4..0000000 --- a/src/tools/imgtool/modules/concept.cpp +++ /dev/null @@ -1,499 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Raphael Nabet -/* - Handlers for concept floppy images - - Disk images are in MESS format. - - Raphael Nabet, 2003 -*/ - -#include "imgtool.h" - -#include "opresolv.h" - -#include -#include -#include -#include - -struct UINT16xE -{ - uint8_t bytes[2]; -}; - -/* - get_UINT16xE - - Read a 16-bit word, whether it is little-endian or big-endian - - little_endian (I): non-zero if word is little-endian, zero if word is - big-endian - word (I): pointer to word to read - - Returns value of word in native format -*/ -static inline uint16_t get_UINT16xE(int little_endian, UINT16xE word) -{ - return little_endian ? (word.bytes[0] | (word.bytes[1] << 8)) : ((word.bytes[0] << 8) | word.bytes[1]); -} - -#if 0 -/* - set_UINT16xE - - Write a 16-bit word, whether it is little-endian or big-endian - - little_endian (I): non-zero if word is little-endian, zero if word is - big-endian - word (O): pointer to word to write - data (I): value to write in word, in native format -*/ -static inline void set_UINT16xE(int little_endian, UINT16xE *word, uint16_t data) -{ - if (little_endian) - { - word->bytes[0] = data & 0xff; - word->bytes[1] = (data >> 8) & 0xff; - } - else - { - word->bytes[0] = (data >> 8) & 0xff; - word->bytes[1] = data & 0xff; - } -} -#endif - -/* - Disk structure: - - Track 0 Sector 0 & 1: bootstrap loader - Track 0 Sector 2 through 5: disk directory - Remaining sectors are used for data. -*/ - -/* - device directory record (Disk sector 2-5) -*/ - -struct concept_vol_hdr_entry -{ - UINT16xE first_block; - UINT16xE next_block; - UINT16xE ftype; - - unsigned char volname[8]; - UINT16xE last_block; - UINT16xE num_files; - UINT16xE last_boot; - UINT16xE last_access; - char mem_flipped; - char disk_flipped; - UINT16xE unused; -}; - -struct concept_file_dir_entry -{ - UINT16xE first_block; - UINT16xE next_block; - UINT16xE ftype; - - unsigned char filename[16]; - UINT16xE last_byte; - UINT16xE last_access; -}; - -struct concept_dev_dir -{ - concept_vol_hdr_entry vol_hdr; - concept_file_dir_entry file_dir[77]; - char unused[20]; -}; - -/* - concept disk image descriptor -*/ -struct concept_image -{ - imgtool::stream *file_handle; /* imgtool file handle */ - concept_dev_dir dev_dir; /* cached copy of device directory */ -}; - -/* - concept catalog iterator, used when imgtool reads the catalog -*/ -struct concept_iterator -{ - concept_image *image; - int index; /* current index */ -}; - - -static imgtoolerr_t concept_image_init(imgtool::image &img, imgtool::stream::ptr &&stream); -static void concept_image_exit(imgtool::image &img); -static void concept_image_info(imgtool::image &img, std::ostream &stream); -static imgtoolerr_t concept_image_beginenum(imgtool::directory &enumeration, const char *path); -static imgtoolerr_t concept_image_nextenum(imgtool::directory &enumeration, imgtool_dirent &ent); -static void concept_image_closeenum(imgtool::directory &enumeration); -static imgtoolerr_t concept_image_freespace(imgtool::partition &partition, uint64_t *size); -static imgtoolerr_t concept_image_readfile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &destf); -#if 0 -static imgtoolerr_t concept_image_writefile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream *sourcef, util::option_resolution *writeoptions); -static imgtoolerr_t concept_image_deletefile(imgtool::partition &partition, const char *filename); -static imgtoolerr_t concept_image_create(const imgtool_module *mod, imgtool::stream *f, util::option_resolution *createoptions); -#endif - -void concept_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_IMAGE_EXTRA_BYTES: info->i = sizeof(concept_image); break; - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(concept_iterator); break; - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "concept"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "Concept floppy disk image"); break; - case IMGTOOLINFO_STR_FILE_EXTENSIONS: strcpy(info->s = imgtool_temp_str(), "img"); 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_OPEN: info->open = concept_image_init; break; - case IMGTOOLINFO_PTR_CLOSE: info->close = concept_image_exit; break; - case IMGTOOLINFO_PTR_INFO: info->info = concept_image_info; break; - case IMGTOOLINFO_PTR_BEGIN_ENUM: info->begin_enum = concept_image_beginenum; break; - case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = concept_image_nextenum; break; - case IMGTOOLINFO_PTR_CLOSE_ENUM: info->close_enum = concept_image_closeenum; break; - case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = concept_image_freespace; break; - case IMGTOOLINFO_PTR_READ_FILE: info->read_file = concept_image_readfile; break; - case IMGTOOLINFO_PTR_WRITE_FILE: /* info->write_file = concept_image_writefile */; break; - case IMGTOOLINFO_PTR_DELETE_FILE: /* info->delete_file = concept_image_deletefile */; break; - case IMGTOOLINFO_PTR_CREATE: /* info->create = concept_image_create */; break; - } -} - -static concept_image *get_concept_image(imgtool::image &image) -{ - return (concept_image *)image.extra_bytes(); -} - -/* - read_physical_record - - Read one 512-byte physical record from a disk image - - file_handle: imgtool file handle - secnum: physical record address - dest: pointer to destination buffer - - Return non-zero on error -*/ -static int read_physical_record(imgtool::stream &file_handle, int secnum, void *dest) -{ - int reply; - - /* seek to sector */ - reply = file_handle.seek(secnum*512, SEEK_SET); - if (reply) - return 1; - /* read it */ - reply = file_handle.read(dest, 512); - if (reply != 512) - return 1; - - return 0; -} - -#ifdef UNUSED_FUNCTION -/* - write_physical_record - - Write one 512-byte physical record to a disk image - - file_handle: imgtool file handle - secnum: logical sector address - src: pointer to source buffer - - Return non-zero on error -*/ -static int write_physical_record(imgtool::stream *file_handle, int secnum, const void *src) -{ - int reply; - - /* seek to sector */ - reply = file_handle->seek(secnum*512, SEEK_SET); - if (reply) - return 1; - /* read it */ - reply = file_handle->write(src, 512); - if (reply != 512) - return 1; - - return 0; -} -#endif - -/* - Search for a file name on a concept_image - - image (I): image reference - filename (I): name of the file to search - entry_index (O): index of file in disk catalog - - Return non-zero on error -*/ -static int get_catalog_entry(concept_image *image, const unsigned char *filename, int *entry_index) -{ - int filename_len = filename[0]; - int i; - - if (filename_len > 15) - /* file name is bad */ - return 1; - - for (i = 0; i < 77; i++) - { - if (!memcmp(filename, image->dev_dir.file_dir[i].filename, filename_len+1)) - { - /* file found */ - *entry_index = i; - return 0; - } - } - - /* file not found */ - return 1; -} - -/* - Open a file as a concept_image. -*/ -static imgtoolerr_t concept_image_init(imgtool::image &img, imgtool::stream::ptr &&stream) -{ - concept_image *image = get_concept_image(img); - int reply; - int i; - unsigned totphysrecs; - - /* read device directory */ - for (i=0; i<4; i++) - { - reply = read_physical_record(*stream, i+2, ((char *) & image->dev_dir)+i*512); - if (reply) - return IMGTOOLERR_READERROR; - } - - /* do primitive checks */ - totphysrecs = get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.vol_hdr.last_block) - - get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.vol_hdr.first_block); - - if ((get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.vol_hdr.first_block) != 0) - || (get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.vol_hdr.next_block) != 6) - || (totphysrecs < 6) /*|| (f->size() != totphysrecs*512)*/ - || (image->dev_dir.vol_hdr.volname[0] > 7)) - { - return IMGTOOLERR_CORRUPTIMAGE; - } - - image->file_handle = stream.release(); - return IMGTOOLERR_SUCCESS; -} - -/* - close a concept_image -*/ -static void concept_image_exit(imgtool::image &img) -{ - /*concept_image *image = get_concept_image(img);*/ -} - -/* - get basic information on a concept_image - - Currently returns the volume name -*/ -static void concept_image_info(imgtool::image &img, std::ostream &stream) -{ - concept_image *image = get_concept_image(img); - char vol_name[8]; - - memcpy(vol_name, image->dev_dir.vol_hdr.volname + 1, image->dev_dir.vol_hdr.volname[0]); - vol_name[image->dev_dir.vol_hdr.volname[0]] = 0; - - stream << vol_name; -} - -/* - Open the disk catalog for enumeration -*/ -static imgtoolerr_t concept_image_beginenum(imgtool::directory &enumeration, const char *path) -{ - concept_iterator *iter; - - iter = (concept_iterator *) enumeration.extra_bytes(); - iter->image = (concept_image *) enumeration.image().extra_bytes(); - iter->index = 0; - return IMGTOOLERR_SUCCESS; -} - -/* - Enumerate disk catalog next entry -*/ -static imgtoolerr_t concept_image_nextenum(imgtool::directory &enumeration, imgtool_dirent &ent) -{ - concept_iterator *iter = (concept_iterator *) enumeration.extra_bytes(); - - - ent.corrupt = 0; - ent.eof = 0; - - if ((iter->image->dev_dir.file_dir[iter->index].filename[0] == 0) || (iter->index > 77)) - { - ent.eof = 1; - } - else if (iter->image->dev_dir.file_dir[iter->index].filename[0] > 15) - { - ent.corrupt = 1; - } - else - { - int len = iter->image->dev_dir.file_dir[iter->index].filename[0]; - const char *type; - - 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; - - /* parse flags */ - switch (get_UINT16xE(iter->image->dev_dir.vol_hdr.disk_flipped, iter->image->dev_dir.file_dir[iter->index].ftype) & 0xf) - { - case 0: - case 8: - type = "DIRHDR"; - break; - case 2: - type = "CODE"; - break; - case 3: - type = "TEXT"; - break; - case 5: - type = "DATA"; - break; - default: - type = "???"; - break; - } - 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) - - get_UINT16xE(iter->image->dev_dir.vol_hdr.disk_flipped, iter->image->dev_dir.file_dir[iter->index].first_block); - - iter->index++; - } - - return (imgtoolerr_t)0; -} - -/* - Free enumerator -*/ -static void concept_image_closeenum(imgtool::directory &enumeration) -{ -} - -/* - Compute free space on disk image -*/ -static imgtoolerr_t concept_image_freespace(imgtool::partition &partition, uint64_t *size) -{ - imgtool::image &img(partition.image()); - concept_image *image = get_concept_image(img); - int free_blocks; - int i; - - /* first get number of data blocks */ - free_blocks = get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.vol_hdr.last_block) - - get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.vol_hdr.next_block); - - /* next substract length of each file */ - for (i=0; (image->dev_dir.file_dir[i].filename[0] != 0) && (i <= 77); i++) - { - free_blocks -= get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.file_dir[i].next_block) - - get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.file_dir[i].first_block); - } - - *size = free_blocks; - - return IMGTOOLERR_SUCCESS; -} - -/* - Extract a file from a concept_image. -*/ -static imgtoolerr_t concept_image_readfile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &destf) -{ - imgtool::image &img(partition.image()); - concept_image *image = get_concept_image(img); - size_t filename_len = strlen(filename); - unsigned char concept_fname[16]; - int catalog_index; - int i; - uint8_t buf[512]; - - if (filename_len > 15) - return IMGTOOLERR_BADFILENAME; - - concept_fname[0] = filename_len; - memcpy(concept_fname+1, filename, filename_len); - - if (get_catalog_entry(image, concept_fname, &catalog_index)) - return IMGTOOLERR_FILENOTFOUND; - - for (i = get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.file_dir[catalog_index].first_block); - i < get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.file_dir[catalog_index].next_block); - i++) - { - if (read_physical_record(*image->file_handle, i, buf)) - return IMGTOOLERR_READERROR; - - if (destf.write(buf, 512) != 512) - return IMGTOOLERR_WRITEERROR; - } - - return (imgtoolerr_t)0; -} - -#if 0 -/* - Add a file to a concept_image. -*/ -static imgtoolerr_t concept_image_writefile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream *sourcef, util::option_resolution *writeoptions) -{ - /* ... */ - - return 0; -} - -/* - Delete a file from a concept_image. -*/ -static imgtoolerr_t concept_image_deletefile(imgtool::partition &partition, const char *filename) -{ - /* ... */ - - return 0; -} - -/* - Create a blank concept_image. -*/ -static imgtoolerr_t concept_image_create(const imgtool_module *mod, imgtool::stream *f, util::option_resolution *createoptions) -{ - /* ... */ - - return 0; -} -#endif diff --git a/src/tools/imgtool/modules/cybiko.cpp b/src/tools/imgtool/modules/cybiko.cpp deleted file mode 100644 index f508e42..0000000 --- a/src/tools/imgtool/modules/cybiko.cpp +++ /dev/null @@ -1,583 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tim Schuerewegen -/* - - Cybiko Classic File System - - (c) 2007 Tim Schuerewegen - -*/ - -#include "imgtool.h" - -#include "opresolv.h" - -#include - -struct cybiko_file_system -{ - imgtool::stream *stream; - uint32_t page_count, page_size, block_count_boot, block_count_file; - uint16_t write_count; -}; - -struct cybiko_iter -{ - uint16_t block; -}; - -struct cfs_file -{ - char name[64]; // name of the file - uint32_t date; // date/time of the file (seconds since 1900/01/01) - uint32_t size; // size of the file - uint32_t blocks; // number of blocks occupied by the file -}; - -enum -{ - BLOCK_TYPE_INVALID, - BLOCK_TYPE_BOOT, - BLOCK_TYPE_FILE -}; - -#define MAX_PAGE_SIZE (264 * 2) - -#define INVALID_FILE_ID 0xFFFF - -enum -{ - FLASH_TYPE_INVALID, - FLASH_TYPE_AT45DB041, - FLASH_TYPE_AT45DB081, - FLASH_TYPE_AT45DB161 -}; - -#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_FILENAME(x) (char*)(x + 7) - -#define FILE_HEADER_SIZE 0x48 - -static cybiko_file_system *get_cfs(imgtool::image &image) -{ - return (cybiko_file_system*)image.extra_bytes(); -} - -// 2208988800 is the number of seconds between 1900/01/01 and 1970/01/01 -typedef util::arbitrary_clock > cybiko_clock; - -imgtool::datetime cybiko_time_crack(uint32_t cfs_time) -{ - cybiko_clock::duration d(cfs_time); - std::chrono::time_point tp(d); - return imgtool::datetime(imgtool::datetime::datetime_type::LOCAL, tp); -} - -uint32_t cybiko_time_setup(const imgtool::datetime &t) -{ - auto cybiko_time_point = cybiko_clock::from_arbitrary_time_point(t.time_point()); - 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) -{ - return crc32( 0, buffer + 8, (block_type == BLOCK_TYPE_BOOT) ? 250 : size - 10); -} - -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); - return swapendian_int16(val); -} - -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); - 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); - if (checksum_calc != checksum_page) return false; - // ok - return true; -} - -static int cfs_block_to_page( cybiko_file_system *cfs, int block_type, uint32_t block, uint32_t *page) -{ - switch (block_type) - { - case BLOCK_TYPE_BOOT : if (page) *page = block; return true; - case BLOCK_TYPE_FILE : if (page) *page = block + cfs->block_count_boot; return true; - default : return false; - } -} - -static int cfs_page_to_block( cybiko_file_system *cfs, uint32_t page, int *block_type, uint32_t *block) -{ - uint32_t tmp = page; - // boot block - if (tmp < cfs->block_count_boot) - { - if (block_type) *block_type = BLOCK_TYPE_BOOT; - if (block) *block = tmp; - return true; - } - tmp -= cfs->block_count_boot; - // file block - if (tmp < cfs->block_count_file) - { - if (block_type) *block_type = BLOCK_TYPE_FILE; - if (block) *block = tmp; - return true; - } - tmp -= cfs->block_count_file; - // error - return false; -} - -static int cfs_page_read( cybiko_file_system *cfs, uint8_t *buffer, uint32_t page) -{ - if (page >= cfs->page_count) return false; - cfs->stream->seek(page * cfs->page_size, SEEK_SET); - cfs->stream->read(buffer, cfs->page_size); - return true; -} - -static int cfs_page_write( cybiko_file_system *cfs, uint8_t *buffer, uint32_t page) -{ - if (page >= cfs->page_count) return false; - cfs->stream->seek(page * cfs->page_size, SEEK_SET); - cfs->stream->write(buffer, cfs->page_size); - return true; -} - -static int cfs_block_read( cybiko_file_system *cfs, uint8_t *buffer, int block_type, uint32_t block) -{ - uint8_t buffer_page[MAX_PAGE_SIZE]; - uint32_t page; - if (!cfs_block_to_page( cfs, block_type, block, &page)) return false; - if (!cfs_page_read( cfs, buffer_page, page)) return false; - memcpy( buffer, buffer_page + 8, cfs->page_size - 10); - return true; -} - -static int cfs_block_write( cybiko_file_system *cfs, uint8_t *buffer, int block_type, uint32_t 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); - if (!cfs_block_to_page( cfs, block_type, block, &page)) return false; - if (!cfs_page_write( cfs, buffer_page, page)) return false; - return true; -} - -static int cfs_file_delete( cybiko_file_system *cfs, uint16_t file_id) -{ - uint8_t buffer[MAX_PAGE_SIZE]; - int i; - for (i=0;iblock_count_file;i++) - { - if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return false; - if (BLOCK_USED(buffer) && (BLOCK_FILE_ID(buffer) == file_id)) - { - buffer[0] &= ~0x80; - if (!cfs_block_write( cfs, buffer, BLOCK_TYPE_FILE, i)) return false; - } - } - return true; -} - -static int cfs_file_info( cybiko_file_system *cfs, uint16_t file_id, cfs_file *file) -{ - uint8_t buffer[MAX_PAGE_SIZE]; - int i; - file->blocks = file->size = 0; - for (i=0;iblock_count_file;i++) - { - if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return false; - if (BLOCK_USED(buffer) && (BLOCK_FILE_ID(buffer) == file_id)) - { - 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->size += buffer[1]; - file->blocks++; - } - } - return (file->blocks > 0) ? true : false; -} - -static int cfs_file_find( cybiko_file_system *cfs, const char *filename, uint16_t *file_id) -{ - uint8_t buffer[MAX_PAGE_SIZE]; - int i; - for (i=0;iblock_count_file;i++) - { - if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return false; - if (BLOCK_USED(buffer) && (strncmp( filename, BLOCK_FILENAME(buffer), 40) == 0)) - { - *file_id = i; - return true; - } - } - return false; -} - -static int cfs_verify(cybiko_file_system &cfs) -{ - uint8_t buffer[MAX_PAGE_SIZE]; - int i, block_type; - for (i = 0; i < cfs.page_count; i++) - { - if (!cfs_page_read(&cfs, buffer, i)) return false; - if (!cfs_page_to_block(&cfs, i, &block_type, NULL)) return false; - if (!page_buffer_verify(buffer, cfs.page_size, block_type)) return false; - } - return true; -} - -static int cfs_init(cybiko_file_system &cfs, imgtool::stream::ptr &&stream, int flash_type) -{ - cfs.stream = stream.release(); - switch (flash_type) - { - case FLASH_TYPE_AT45DB041 : cfs.page_count = 2048; cfs.page_size = 264; break; - case FLASH_TYPE_AT45DB081 : cfs.page_count = 4096; cfs.page_size = 264; break; - case FLASH_TYPE_AT45DB161 : cfs.page_count = 4096; cfs.page_size = 528; break; - default : return false; - } - cfs.block_count_boot = 5; - cfs.block_count_file = cfs.page_count - cfs.block_count_boot; - cfs.write_count = 0; - return true; -} - -static int cfs_format( cybiko_file_system *cfs) -{ - uint8_t buffer[MAX_PAGE_SIZE]; - int i; - // boot blocks - memset( buffer, 0xFF, sizeof( buffer)); - for (i=0;iblock_count_boot;i++) - { - if (!cfs_block_write( cfs, buffer, BLOCK_TYPE_BOOT, i)) return false; - } - // file blocks - memset( buffer, 0xFF, sizeof( buffer)); - buffer[0] &= ~0x80; - for (i=0;iblock_count_file;i++) - { - if (!cfs_block_write( cfs, buffer, BLOCK_TYPE_FILE, i)) return false; - } - // ok - return true; -} - -static uint16_t cfs_calc_free_blocks( cybiko_file_system *cfs) -{ - uint8_t buffer[MAX_PAGE_SIZE]; - int i; - uint16_t blocks = 0; - for (i=0;iblock_count_file;i++) - { - if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return 0; - if (!BLOCK_USED(buffer)) blocks++; - } - return blocks; -} - -static uint32_t cfs_calc_free_space( cybiko_file_system *cfs, uint16_t blocks) -{ - uint32_t free_space; - free_space = blocks * (cfs->page_size - 0x10); - if (free_space > 0) free_space -= FILE_HEADER_SIZE; - return free_space; -} - -static int flash_size_to_flash_type( size_t size) -{ - switch (size) - { - case 0x084000 : return FLASH_TYPE_AT45DB041; - case 0x108000 : return FLASH_TYPE_AT45DB081; - case 0x210000 : return FLASH_TYPE_AT45DB161; - default : return FLASH_TYPE_INVALID; - } -} - -static int flash_option_to_flash_type( int option) -{ - switch (option) - { - case 0 : return FLASH_TYPE_AT45DB041; - case 1 : return FLASH_TYPE_AT45DB081; - case 2 : return FLASH_TYPE_AT45DB161; - default : return FLASH_TYPE_INVALID; - } -} - -static imgtoolerr_t cybiko_image_open(imgtool::image &image, imgtool::stream::ptr &&stream) -{ - cybiko_file_system *cfs = get_cfs(image); - int flash_type; - // init - flash_type = flash_size_to_flash_type(stream->size()); - if (!cfs_init(*cfs, std::move(stream), flash_type)) return IMGTOOLERR_CORRUPTIMAGE; - // verify - if (!cfs_verify(*cfs)) return IMGTOOLERR_CORRUPTIMAGE; - // ok - return IMGTOOLERR_SUCCESS; -} - -static void cybiko_image_close(imgtool::image &image) -{ - cybiko_file_system *cfs = get_cfs(image); - delete cfs->stream; -} - -static imgtoolerr_t cybiko_image_create(imgtool::image &image, imgtool::stream::ptr &&stream, util::option_resolution *opts) -{ - cybiko_file_system *cfs = get_cfs(image); - int flash_type; - // init - flash_type = flash_option_to_flash_type(opts->lookup_int('F')); - if (!cfs_init(*cfs, std::move(stream), flash_type)) return IMGTOOLERR_CORRUPTIMAGE; - // format - if (!cfs_format(cfs)) return IMGTOOLERR_CORRUPTIMAGE; - // ok - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t cybiko_image_begin_enum(imgtool::directory &enumeration, const char *path) -{ - cybiko_iter *iter = (cybiko_iter*)enumeration.extra_bytes(); - iter->block = 0; - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t cybiko_image_next_enum(imgtool::directory &enumeration, imgtool_dirent &ent) -{ - imgtool::image &image(enumeration.image()); - cybiko_file_system *cfs = get_cfs(image); - cybiko_iter *iter = (cybiko_iter*)enumeration.extra_bytes(); - uint8_t buffer[MAX_PAGE_SIZE]; - uint16_t file_id = INVALID_FILE_ID; - cfs_file file; - // find next file - while (iter->block < cfs->block_count_file) - { - if (!cfs_block_read(cfs, buffer, BLOCK_TYPE_FILE, iter->block++)) return IMGTOOLERR_READERROR; - if (BLOCK_USED(buffer) && (BLOCK_PART_ID(buffer) == 0)) - { - file_id = BLOCK_FILE_ID(buffer); - break; - } - } - // get file information - if ((file_id != INVALID_FILE_ID) && cfs_file_info(cfs, file_id, &file)) - { - strcpy(ent.filename, file.name); - ent.filesize = file.size; - ent.lastmodified_time = cybiko_time_crack(file.date); - ent.filesize = file.size; - } - else - { - ent.eof = 1; - } - // ok - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t cybiko_image_free_space(imgtool::partition &partition, uint64_t *size) -{ - imgtool::image &image(partition.image()); - cybiko_file_system *cfs = get_cfs(image); - if (size) *size = cfs_calc_free_space( cfs, cfs_calc_free_blocks( cfs)); - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t cybiko_image_read_file(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &destf) -{ - imgtool::image &image(partition.image()); - cybiko_file_system *cfs = get_cfs(image); - uint8_t buffer[MAX_PAGE_SIZE]; - uint16_t file_id, part_id = 0, old_part_id; - int i; - // find file - if (!cfs_file_find( cfs, filename, &file_id)) return IMGTOOLERR_FILENOTFOUND; - // read file - do - { - old_part_id = part_id; - for (i=0;iblock_count_file;i++) - { - if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return IMGTOOLERR_READERROR; - if (BLOCK_USED(buffer) && (BLOCK_FILE_ID(buffer) == file_id) && (BLOCK_PART_ID(buffer) == part_id)) - { - destf.write(buffer + 6 + ((part_id == 0) ? FILE_HEADER_SIZE : 0), buffer[1]); - part_id++; - } - } - } while (old_part_id != part_id); - // ok - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t cybiko_image_write_file(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &sourcef, util::option_resolution *opts) -{ - imgtool::image &image(partition.image()); - cybiko_file_system *cfs = get_cfs(image); - uint8_t buffer[MAX_PAGE_SIZE]; - uint16_t file_id, part_id = 0, free_blocks; - uint64_t bytes_left; - cfs_file file; - int i; - // find file - if (!cfs_file_find(cfs, filename, &file_id)) file_id = INVALID_FILE_ID; - // check free space - free_blocks = cfs_calc_free_blocks( cfs); - if (file_id != INVALID_FILE_ID) - { - if (!cfs_file_info(cfs, file_id, &file)) return IMGTOOLERR_UNEXPECTED; - free_blocks += file.blocks; - } - if (cfs_calc_free_space(cfs, free_blocks) < sourcef.size()) return IMGTOOLERR_NOSPACE; - // delete file - if (file_id != INVALID_FILE_ID) - { - if (!cfs_file_delete( cfs, file_id)) return IMGTOOLERR_UNEXPECTED; - } - // create/write destination file - bytes_left = sourcef.size(); - i = 0; - while ((bytes_left > 0) && (i < cfs->block_count_file)) - { - if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return IMGTOOLERR_READERROR; - if (!BLOCK_USED(buffer)) - { - if (part_id == 0) file_id = i; - memset( buffer, 0xFF, cfs->page_size - 0x10); - 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); - 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))); - sourcef.read(buffer + 6 + FILE_HEADER_SIZE, buffer[1]); - } - else - { - sourcef.read(buffer + 6, buffer[1]); - } - if (!cfs_block_write( cfs, buffer, BLOCK_TYPE_FILE, i)) return IMGTOOLERR_WRITEERROR; - bytes_left -= buffer[1]; - part_id++; - } - i++; - } - // ok - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t cybiko_image_delete_file(imgtool::partition &partition, const char *filename) -{ - imgtool::image &image(partition.image()); - cybiko_file_system *cfs = get_cfs(image); - uint16_t file_id; - // find file - if (!cfs_file_find( cfs, filename, &file_id)) return IMGTOOLERR_FILENOTFOUND; - // delete file - if (!cfs_file_delete( cfs, file_id)) return IMGTOOLERR_UNEXPECTED; - // ok - return IMGTOOLERR_SUCCESS; -} - -OPTION_GUIDE_START( cybiko_image_createimage_optguide ) - OPTION_ENUM_START( 'F', "flash", "Flash Type" ) - OPTION_ENUM( 0, "AT45DB041", "AT45DB041 (528 KByte)" ) - OPTION_ENUM( 1, "AT45DB081", "AT45DB081 (1056 KByte)" ) - OPTION_ENUM( 2, "AT45DB161", "AT45DB161 (2112 KByte)" ) - OPTION_ENUM_END -OPTION_GUIDE_END - -//OPTION_GUIDE_START( cybiko_image_writefile_optguide ) -// OPTION_INT( 'B', "boot", "Boot Flag" ) -//OPTION_GUIDE_END - -void cybiko_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_IMAGE_EXTRA_BYTES : info->i = sizeof( cybiko_file_system); break; - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES : info->i = sizeof( cybiko_iter); break; -// case IMGTOOLINFO_INT_SUPPORTS_CREATION_TIME : info->i = 1; break; - case IMGTOOLINFO_INT_SUPPORTS_LASTMODIFIED_TIME : info->i = 1; break; -// case IMGTOOLINFO_INT_BLOCK_SIZE : info->i = 264; break; - // --- the following bits of info are returned as pointers to data or functions --- - case IMGTOOLINFO_PTR_OPEN : info->open = cybiko_image_open; break; - case IMGTOOLINFO_PTR_CREATE : info->create = cybiko_image_create; break; - case IMGTOOLINFO_PTR_CLOSE : info->close = cybiko_image_close; break; - case IMGTOOLINFO_PTR_BEGIN_ENUM : info->begin_enum = cybiko_image_begin_enum; break; - case IMGTOOLINFO_PTR_NEXT_ENUM : info->next_enum = cybiko_image_next_enum; break; - case IMGTOOLINFO_PTR_FREE_SPACE : info->free_space = cybiko_image_free_space; break; - case IMGTOOLINFO_PTR_READ_FILE : info->read_file = cybiko_image_read_file; break; - case IMGTOOLINFO_PTR_WRITE_FILE : info->write_file = cybiko_image_write_file; break; - case IMGTOOLINFO_PTR_DELETE_FILE : info->delete_file = cybiko_image_delete_file; break; - case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE : info->createimage_optguide = &cybiko_image_createimage_optguide; break; -// case IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE : info->writefile_optguide = cybiko_image_writefile_optguide; break; - // --- the following bits of info are returned as NULL-terminated strings --- - case IMGTOOLINFO_STR_NAME : strcpy( info->s = imgtool_temp_str(), "cybiko"); break; - case IMGTOOLINFO_STR_DESCRIPTION : strcpy( info->s = imgtool_temp_str(), "Cybiko Classic File System"); break; - case IMGTOOLINFO_STR_FILE : strcpy( info->s = imgtool_temp_str(), __FILE__); break; - case IMGTOOLINFO_STR_FILE_EXTENSIONS : strcpy( info->s = imgtool_temp_str(), "bin,nv"); break; - case IMGTOOLINFO_STR_EOLN : strcpy( info->s = imgtool_temp_str(), "\r\n"); break; - case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC : strcpy( info->s = imgtool_temp_str(), "F[0]-2"); break; -// case IMGTOOLINFO_STR_WRITEFILE_OPTSPEC : strcpy( info->s = imgtool_temp_str(), "B[0]-1"); break; - } -} diff --git a/src/tools/imgtool/modules/cybikoxt.cpp b/src/tools/imgtool/modules/cybikoxt.cpp deleted file mode 100644 index 8c2980d..0000000 --- a/src/tools/imgtool/modules/cybikoxt.cpp +++ /dev/null @@ -1,529 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tim Schuerewegen -/* - - Cybiko Xtreme File System - - (c) 2010 Tim Schuerewegen - -*/ - -#include "imgtool.h" - -#include - -struct cybiko_file_system -{ - imgtool::stream *stream; - uint32_t page_count, page_size, block_count_boot, block_count_file; - uint16_t write_count; -}; - -struct cybiko_iter -{ - uint16_t block; -}; - -struct cfs_file -{ - char name[64]; // name of the file - uint32_t date; // date/time of the file (seconds since 1900/01/01) - uint32_t size; // size of the file - uint32_t blocks; // number of blocks occupied by the file -}; - -enum -{ - BLOCK_TYPE_INVALID, - BLOCK_TYPE_BOOT, - BLOCK_TYPE_FILE -}; - -#define MAX_PAGE_SIZE (264 * 2) - -#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_FILENAME(x) (char*)(x + 7) - -#define FILE_HEADER_SIZE 0x48 - -static cybiko_file_system *get_cfs(imgtool::image &image) -{ - return (cybiko_file_system*)image.extra_bytes(); -} - -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) -{ - int i; - uint32_t val = 0; - for (i = 0; i < size; i++) - { - val = (val ^ data[i] ^ i) << 1; - val = val | ((val >> 16) & 0x0001); - } - return val; -} - -static int page_buffer_verify( uint8_t *buffer, uint32_t size, int block_type) -{ - // checksum - if (block_type == BLOCK_TYPE_FILE) - { - uint32_t checksum_page, checksum_calc; - checksum_calc = page_buffer_calc_checksum( buffer + 2, size - 2); - checksum_page = buffer_read_16_be( buffer + 0); - if (checksum_calc != checksum_page) return false; - } - // ok - return true; -} - -static int cfs_block_to_page( cybiko_file_system *cfs, int block_type, uint32_t block, uint32_t *page) -{ - switch (block_type) - { - case BLOCK_TYPE_BOOT : if (page) *page = block; return true; - case BLOCK_TYPE_FILE : if (page) *page = block + cfs->block_count_boot; return true; - default : return false; - } -} - -static int cfs_page_to_block( cybiko_file_system *cfs, uint32_t page, int *block_type, uint32_t *block) -{ - uint32_t tmp = page; - // boot block - if (tmp < cfs->block_count_boot) - { - if (block_type) *block_type = BLOCK_TYPE_BOOT; - if (block) *block = tmp; - return true; - } - tmp -= cfs->block_count_boot; - // file block - if (tmp < cfs->block_count_file) - { - if (block_type) *block_type = BLOCK_TYPE_FILE; - if (block) *block = tmp; - return true; - } - tmp -= cfs->block_count_file; - // error - return false; -} - -static int cfs_page_read( cybiko_file_system *cfs, uint8_t *buffer, uint32_t page) -{ - if (page >= cfs->page_count) return false; - cfs->stream->seek(page * cfs->page_size, SEEK_SET); - cfs->stream->read(buffer, cfs->page_size); - return true; -} - -static int cfs_page_write( cybiko_file_system *cfs, uint8_t *buffer, uint32_t page) -{ - if (page >= cfs->page_count) return false; - cfs->stream->seek(page * cfs->page_size, SEEK_SET); - cfs->stream->write(buffer, cfs->page_size); - return true; -} - -static int cfs_block_read( cybiko_file_system *cfs, uint8_t *buffer, int block_type, uint32_t block) -{ - uint8_t buffer_page[MAX_PAGE_SIZE]; - uint32_t page; - if (!cfs_block_to_page( cfs, block_type, block, &page)) return false; - if (!cfs_page_read( cfs, buffer_page, page)) return false; - memcpy( buffer, buffer_page + 2, cfs->page_size - 2); - return true; -} - -static int cfs_block_write( cybiko_file_system *cfs, uint8_t *buffer, int block_type, uint32_t block) -{ - uint8_t buffer_page[MAX_PAGE_SIZE]; - uint32_t page; - uint16_t checksum; - memcpy( buffer_page + 2, buffer, cfs->page_size - 2); - if (block_type == BLOCK_TYPE_BOOT) - { - checksum = 0xFFFF; - } - else - { - checksum = page_buffer_calc_checksum( buffer_page + 2, cfs->page_size - 2); - } - buffer_write_16_be( 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; -} - -static int cfs_file_delete( cybiko_file_system *cfs, uint16_t file_id) -{ - uint8_t buffer[MAX_PAGE_SIZE]; - int i; - for (i=0;iblock_count_file;i++) - { - if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return false; - if (BLOCK_USED(buffer) && (BLOCK_FILE_ID(buffer) == file_id)) - { - buffer[0] &= ~0x80; - if (!cfs_block_write( cfs, buffer, BLOCK_TYPE_FILE, i)) return false; - } - } - return true; -} - -static int cfs_file_info( cybiko_file_system *cfs, uint16_t file_id, cfs_file *file) -{ - uint8_t buffer[MAX_PAGE_SIZE]; - int i; - file->blocks = file->size = 0; - for (i=0;iblock_count_file;i++) - { - if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return false; - if (BLOCK_USED(buffer) && (BLOCK_FILE_ID(buffer) == file_id)) - { - 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->size += buffer[1]; - file->blocks++; - } - } - return (file->blocks > 0) ? true : false; -} - -static int cfs_file_find( cybiko_file_system *cfs, const char *filename, uint16_t *file_id) -{ - uint8_t buffer[MAX_PAGE_SIZE]; - int i; - for (i=0;iblock_count_file;i++) - { - if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return false; - if (BLOCK_USED(buffer) && (BLOCK_PART_ID(buffer) == 0) && (strcmp( filename, BLOCK_FILENAME(buffer)) == 0)) - { - *file_id = i; - return true; - } - } - return false; -} - -static bool cfs_verify(cybiko_file_system &cfs) -{ - uint8_t buffer[MAX_PAGE_SIZE]; - int i, block_type; - for (i = 0; i < cfs.page_count; i++) - { - if (!cfs_page_read(&cfs, buffer, i)) return false; - if (!cfs_page_to_block(&cfs, i, &block_type, NULL)) return false; - if (!page_buffer_verify(buffer, cfs.page_size, block_type)) return false; - } - return true; -} - -static bool cfs_init(cybiko_file_system &cfs, imgtool::stream::ptr &&stream) -{ - cfs.stream = stream.release(); - cfs.page_count = 2005; - cfs.page_size = 258; - cfs.block_count_boot = 5; - cfs.block_count_file = cfs.page_count - cfs.block_count_boot; - cfs.write_count = 0; - return true; -} - -static int cfs_format(cybiko_file_system *cfs) -{ - uint8_t buffer[MAX_PAGE_SIZE]; - int i; - // boot blocks - memset( buffer, 0xFF, sizeof( buffer)); - for (i=0;iblock_count_boot;i++) - { - if (!cfs_block_write( cfs, buffer, BLOCK_TYPE_BOOT, i)) return false; - } - // file blocks - memset( buffer, 0xFF, sizeof( buffer)); - buffer[0] &= ~0x80; - for (i=0;iblock_count_file;i++) - { - if (!cfs_block_write( cfs, buffer, BLOCK_TYPE_FILE, i)) return false; - } - // padding - buffer[0] = 0xFF; - for (i=0;i<0x1B56;i++) - { - cfs->stream->write(buffer, 1); - } - // ok - return true; -} - -static uint16_t cfs_calc_free_blocks( cybiko_file_system *cfs) -{ - uint8_t buffer[MAX_PAGE_SIZE]; - int i; - uint16_t blocks = 0; - for (i=0;iblock_count_file;i++) - { - if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return 0; - if (!BLOCK_USED(buffer)) blocks++; - } - return blocks; -} - -static uint32_t cfs_calc_free_space( cybiko_file_system *cfs, uint16_t blocks) -{ - uint32_t free_space; - free_space = blocks * ((cfs->page_size - 2) - 6); - if (free_space > 0) free_space -= FILE_HEADER_SIZE; - return free_space; -} - -static imgtoolerr_t cybiko_image_open(imgtool::image &image, imgtool::stream::ptr &&stream) -{ - cybiko_file_system *cfs = get_cfs(image); - // init - if (!cfs_init(*cfs, std::move(stream))) return IMGTOOLERR_CORRUPTIMAGE; - // verify - if (!cfs_verify(*cfs)) return IMGTOOLERR_CORRUPTIMAGE; - // ok - return IMGTOOLERR_SUCCESS; -} - -static void cybiko_image_close(imgtool::image &image) -{ - cybiko_file_system *cfs = get_cfs(image); - delete cfs->stream; -} - -static imgtoolerr_t cybiko_image_create(imgtool::image &image, imgtool::stream::ptr &&stream, util::option_resolution *opts) -{ - cybiko_file_system *cfs = get_cfs(image); - // init - if (!cfs_init(*cfs, std::move(stream))) return IMGTOOLERR_CORRUPTIMAGE; - // format - if (!cfs_format(cfs)) return IMGTOOLERR_CORRUPTIMAGE; - // ok - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t cybiko_image_begin_enum(imgtool::directory &enumeration, const char *path) -{ - cybiko_iter *iter = (cybiko_iter*)enumeration.extra_bytes(); - iter->block = 0; - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t cybiko_image_next_enum(imgtool::directory &enumeration, imgtool_dirent &ent) -{ - imgtool::image &image(enumeration.image()); - cybiko_file_system *cfs = get_cfs(image); - cybiko_iter *iter = (cybiko_iter*)enumeration.extra_bytes(); - uint8_t buffer[MAX_PAGE_SIZE]; - uint16_t file_id = INVALID_FILE_ID; - cfs_file file; - // find next file - while (iter->block < cfs->block_count_file) - { - if (!cfs_block_read(cfs, buffer, BLOCK_TYPE_FILE, iter->block++)) return IMGTOOLERR_READERROR; - if (BLOCK_USED(buffer) && (BLOCK_PART_ID(buffer) == 0)) - { - file_id = BLOCK_FILE_ID(buffer); - break; - } - } - // get file information - if ((file_id != INVALID_FILE_ID) && cfs_file_info(cfs, file_id, &file)) - { - strcpy(ent.filename, file.name); - ent.filesize = file.size; - ent.lastmodified_time = cybiko_time_crack(file.date); - ent.filesize = file.size; - } - else - { - ent.eof = 1; - } - // ok - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t cybiko_image_free_space(imgtool::partition &partition, uint64_t *size) -{ - imgtool::image &image(partition.image()); - cybiko_file_system *cfs = get_cfs(image); - if (size) *size = cfs_calc_free_space( cfs, cfs_calc_free_blocks( cfs)); - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t cybiko_image_read_file(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &destf) -{ - imgtool::image &image(partition.image()); - cybiko_file_system *cfs = get_cfs(image); - uint8_t buffer[MAX_PAGE_SIZE]; - uint16_t file_id, part_id = 0, old_part_id; - int i; - // check filename - if (strlen( filename) > 58) return IMGTOOLERR_BADFILENAME; - // find file - if (!cfs_file_find( cfs, filename, &file_id)) return IMGTOOLERR_FILENOTFOUND; - // read file - do - { - old_part_id = part_id; - for (i=0;iblock_count_file;i++) - { - if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return IMGTOOLERR_READERROR; - if (BLOCK_USED(buffer) && (BLOCK_FILE_ID(buffer) == file_id) && (BLOCK_PART_ID(buffer) == part_id)) - { - destf.write(buffer + 6 + ((part_id == 0) ? FILE_HEADER_SIZE : 0), buffer[1]); - part_id++; - } - } - } while (old_part_id != part_id); - // ok - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t cybiko_image_write_file(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &sourcef, util::option_resolution *opts) -{ - imgtool::image &image(partition.image()); - cybiko_file_system *cfs = get_cfs(image); - uint8_t buffer[MAX_PAGE_SIZE]; - uint16_t file_id, part_id = 0, free_blocks; - uint64_t bytes_left; - cfs_file file; - int i; - // check filename - if (strlen( filename) > 58) return IMGTOOLERR_BADFILENAME; - // find file - if (!cfs_file_find( cfs, filename, &file_id)) file_id = INVALID_FILE_ID; - // check free space - free_blocks = cfs_calc_free_blocks(cfs); - if (file_id != INVALID_FILE_ID) - { - if (!cfs_file_info(cfs, file_id, &file)) return IMGTOOLERR_UNEXPECTED; - free_blocks += file.blocks; - } - if (cfs_calc_free_space(cfs, free_blocks) < sourcef.size()) return IMGTOOLERR_NOSPACE; - // delete file - if (file_id != INVALID_FILE_ID) - { - if (!cfs_file_delete(cfs, file_id)) return IMGTOOLERR_UNEXPECTED; - } - // create/write destination file - bytes_left = sourcef.size(); - i = 0; - while (i < cfs->block_count_file) - { - if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return IMGTOOLERR_READERROR; - if (!BLOCK_USED(buffer)) - { - if (part_id == 0) file_id = i; - memset( buffer, 0xFF, cfs->page_size - 0x02); - 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); - 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))); - sourcef.read(buffer + 6 + FILE_HEADER_SIZE, buffer[1]); - } - else - { - sourcef.read(buffer + 6, buffer[1]); - } - if (!cfs_block_write( cfs, buffer, BLOCK_TYPE_FILE, i)) return IMGTOOLERR_WRITEERROR; - bytes_left -= buffer[1]; - if (bytes_left == 0) break; - part_id++; - } - i++; - } - // ok - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t cybiko_image_delete_file(imgtool::partition &partition, const char *filename) -{ - imgtool::image &image(partition.image()); - cybiko_file_system *cfs = get_cfs(image); - uint16_t file_id; - // check filename - if (strlen(filename) > 58) return IMGTOOLERR_BADFILENAME; - // find file - if (!cfs_file_find(cfs, filename, &file_id)) return IMGTOOLERR_FILENOTFOUND; - // delete file - if (!cfs_file_delete(cfs, file_id)) return IMGTOOLERR_UNEXPECTED; - // ok - return IMGTOOLERR_SUCCESS; -} - -void cybikoxt_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_IMAGE_EXTRA_BYTES : info->i = sizeof( cybiko_file_system); break; - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES : info->i = sizeof( cybiko_iter); break; -// case IMGTOOLINFO_INT_SUPPORTS_CREATION_TIME : info->i = 1; break; - case IMGTOOLINFO_INT_SUPPORTS_LASTMODIFIED_TIME : info->i = 1; break; -// case IMGTOOLINFO_INT_BLOCK_SIZE : info->i = 264; break; - // --- the following bits of info are returned as pointers to data or functions --- - case IMGTOOLINFO_PTR_OPEN : info->open = cybiko_image_open; break; - case IMGTOOLINFO_PTR_CREATE : info->create = cybiko_image_create; break; - case IMGTOOLINFO_PTR_CLOSE : info->close = cybiko_image_close; break; - case IMGTOOLINFO_PTR_BEGIN_ENUM : info->begin_enum = cybiko_image_begin_enum; break; - case IMGTOOLINFO_PTR_NEXT_ENUM : info->next_enum = cybiko_image_next_enum; break; - case IMGTOOLINFO_PTR_FREE_SPACE : info->free_space = cybiko_image_free_space; break; - case IMGTOOLINFO_PTR_READ_FILE : info->read_file = cybiko_image_read_file; break; - case IMGTOOLINFO_PTR_WRITE_FILE : info->write_file = cybiko_image_write_file; break; - case IMGTOOLINFO_PTR_DELETE_FILE : info->delete_file = cybiko_image_delete_file; break; - // --- the following bits of info are returned as NULL-terminated strings --- - case IMGTOOLINFO_STR_NAME : strcpy( info->s = imgtool_temp_str(), "cybikoxt"); break; - case IMGTOOLINFO_STR_DESCRIPTION : strcpy( info->s = imgtool_temp_str(), "Cybiko Xtreme File System"); break; - case IMGTOOLINFO_STR_FILE : strcpy( info->s = imgtool_temp_str(), __FILE__); break; - case IMGTOOLINFO_STR_FILE_EXTENSIONS : strcpy( info->s = imgtool_temp_str(), "bin,nv"); break; - case IMGTOOLINFO_STR_EOLN : strcpy( info->s = imgtool_temp_str(), "\r\n"); break; - } -} diff --git a/src/tools/imgtool/modules/dgndos.cpp b/src/tools/imgtool/modules/dgndos.cpp deleted file mode 100644 index 13fbbfc..0000000 --- a/src/tools/imgtool/modules/dgndos.cpp +++ /dev/null @@ -1,1256 +0,0 @@ -// 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 -#include -#include - -#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.c_str(), 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= 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; iMAX_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 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 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 = SUGGESTION_RECOMMENDED; - suggestions[0].filter = filter_eoln_getinfo; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = NULL; - } - else if (strcmp(ent.block.header.filename+8,"BAS") == 0) - { - /* tokenized BASIC file */ - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = filter_dragonbas_getinfo; - } - } - else - { - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = filter_eoln_getinfo; - suggestions[2].viability = 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; ii = 1; break; - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(struct dgndos_direnum); break; - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - 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 deleted file mode 100644 index 3b5b670..0000000 --- a/src/tools/imgtool/modules/fat.cpp +++ /dev/null @@ -1,2111 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Raphael Nabet -/**************************************************************************** - - fat.cpp - - PC FAT disk images - -***************************************************************************** - - Master boot record format: - - Offset Length Description - ------ ------ ----------- - 0 446 Boot machine code - 446 16 Partion #1 info - 462 16 Partion #2 info - 478 16 Partion #3 info - 494 16 Partion #4 info - 510 2 Magic bytes (0x55 0xAA) - - - Partition info format: - - Offset Length Description - ------ ------ ----------- - 0 1 Active byte (0x80=active 0x00=inactive) - 1 1 Starting head - 2 1 Starting sector (bits 5-0) and high bits of starting track (bits 6-5) - 3 1 Low bits of starting track - 4 1 Partition type: - 0x00 Unused - 0x?1 FAT12 (0-15 MB) - 0x?2 XENIX - 0x?4 FAT16 (16-32 MB) - 0x?6 FAT16` (32 MB-2 GB) - 0x?7 HPFS or NTFS - 0x?A Boot Manager - 0x?B FAT32 (512 MB-2 TB) - 0x?C FAT32 (512 MB-2 TB LBA) - 0x1? OS/2 Boot manager/Win95 hidden - 0xC? DR-DOS secured partition - 0xD? Multiuser DOS secured partition - 0xE? SpeedStor extended partition - 5 1 Ending head - 6 1 Ending sector (bits 5-0) and high bits of ending track (bits 6-5) - 7 1 Low bits of ending track - 8 4 Sector index of beginning of partition - 12 4 Total sectors in partition - - - Boot sector format: - - Offset Length Description - ------ ------ ----------- - 0 3 Jump instruction (to skip over header on boot) - 3 8 OEM Name - 11 2 Bytes per sector - 13 1 Sectors per cluster - 14 2 Reserved sector count (including boot sector) - 16 1 Number of FATs (file allocation tables) - 17 2 Number of root directory entries - 19 2 Total sectors (bits 0-15) - 21 1 Media descriptor - 22 2 Sectors per FAT - 24 2 Sectors per track - 26 2 Number of heads - 28 4 Hidden sectors - 32 4 Total sectors (bits 16-47) - 36 1 Physical drive number - 37 1 Current head - 38 1 Signature - 39 4 ID - 43 11 Volume Label - 54 8 FAT file system type - 62 448 Boot machine code - 510 2 Magic bytes (0x55 0xAA) - - For more information: - http://support.microsoft.com/kb/q140418/ - - - Directory Entry Format: - - Offset Length Description - ------ ------ ----------- - 0 8 DOS File Name (padded with spaces) - 8 3 DOS File Extension (padded with spaces) - 11 1 File Attributes - 12 2 Unknown - 14 4 Time of Creation - 18 2 Last Access Time - 20 2 EA-Index (OS/2 stuff) - 22 4 Last Modified Time - 26 2 First Cluster - 28 4 File Size - - - Dates and times are stored in separate words; when together, the time is - first and the date is second. - - Time: - bits 15-11 Hour - bits 10- 5 Minute - bits 4- 0 Second / 2 - - Date: - bits 15- 9 Year - 1980 - bits 8- 5 Month - bits 4- 0 Day - - LFN Entry Format: - - Offset Length Description - ------ ------ ----------- - 0 1 Sequence Number (bit 6 is set on highest sequence) - 1 10 Name characters (five UTF-16LE chars) - 11 1 Attributes (always 0x0F) - 12 1 Reserved (always 0x00) - 13 1 Checksum of short filename entry - 14 12 Name characters (six UTF-16LE chars) - 26 2 Entry Cluster (always 0x00) - 28 4 Name characters (two UTF-16LE chars) - - Valid characters in DOS file names: - - Upper case letters A-Z - - Numbers 0-9 - - Space (though there is no way to identify a trailing space) - - ! # $ % & ( ) - @ ^ _ ` { } ~ - - Characters 128-255 (though the code page is indeterminate) - - For more information: - http://en.wikipedia.org/wiki/File_Allocation_Table - -****************************************************************************/ - -#include "fat.h" - -#include "formats/imageutl.h" - -#include "corestr.h" -#include "unicode.h" - -#include -#include -#include - -#define FAT_DIRENT_SIZE 32 -#define FAT_SECLEN 512 - -#define LOG(x) - -struct fat_partition_info -{ - uint32_t fat_bits; - uint32_t sectors_per_cluster; - uint32_t cluster_size; - uint32_t reserved_sectors; - uint32_t fat_count; - uint32_t root_entries; - uint32_t sectors_per_fat; - uint64_t total_sectors; - uint32_t total_clusters; -}; - -struct fat_file -{ - unsigned int root : 1; - unsigned int directory : 1; - unsigned int eof : 1; - uint32_t index; - uint32_t filesize; - uint32_t first_cluster; - uint32_t parent_first_cluster; - uint32_t cluster; - uint32_t cluster_index; - uint32_t dirent_sector_index; - uint32_t dirent_sector_offset; -}; - -struct fat_dirent -{ - char long_filename[512]; - char short_filename[13]; - unsigned int directory : 1; - unsigned int eof : 1; - uint32_t filesize; - uint32_t first_cluster; - uint32_t dirent_sector_index; - uint32_t dirent_sector_offset; - imgtool::datetime creation_time; - imgtool::datetime lastmodified_time; -}; - -struct fat_freeentry_info -{ - uint32_t required_size; - uint32_t candidate_position; - uint32_t position; -}; - -struct fat_mediatype -{ - uint8_t media_descriptor; - uint8_t heads; - uint8_t tracks; - uint8_t sectors; -}; - -enum creation_policy_t -{ - CREATE_NONE, - CREATE_FILE, - CREATE_DIR -}; - - - -static const fat_mediatype known_media[] = -{ - { 0xF0, 2, 80, 36 }, - { 0xF0, 2, 80, 18 }, - { 0xF9, 2, 80, 9 }, - { 0xF9, 2, 80, 15 }, - { 0xFD, 2, 40, 9 }, - { 0xFF, 2, 40, 8 }, - { 0xFC, 1, 40, 9 }, - { 0xFE, 1, 40, 8 }, - { 0xF8, 0, 0, 0 } -}; - -/* boot sector code taken from FreeDOS */ -static const uint8_t boot_sector_code[] = -{ - 0xfa, 0xfc, 0x31, 0xc0, 0x8e, 0xd8, 0xbd, 0x00, 0x7c, 0xb8, 0xe0, 0x1f, - 0x8e, 0xc0, 0x89, 0xee, 0x89, 0xef, 0xb9, 0x00, 0x01, 0xf3, 0xa5, 0xea, - 0x5e, 0x7c, 0xe0, 0x1f, 0x00, 0x00, 0x60, 0x00, 0x8e, 0xd8, 0x8e, 0xd0, - 0x8d, 0x66, 0xa0, 0xfb, 0x80, 0x7e, 0x24, 0xff, 0x75, 0x03, 0x88, 0x56, - 0x24, 0xc7, 0x46, 0xc0, 0x10, 0x00, 0xc7, 0x46, 0xc2, 0x01, 0x00, 0x8b, - 0x76, 0x1c, 0x8b, 0x7e, 0x1e, 0x03, 0x76, 0x0e, 0x83, 0xd7, 0x00, 0x89, - 0x76, 0xd2, 0x89, 0x7e, 0xd4, 0x8a, 0x46, 0x10, 0x98, 0xf7, 0x66, 0x16, - 0x01, 0xc6, 0x11, 0xd7, 0x89, 0x76, 0xd6, 0x89, 0x7e, 0xd8, 0x8b, 0x5e, - 0x0b, 0xb1, 0x05, 0xd3, 0xeb, 0x8b, 0x46, 0x11, 0x31, 0xd2, 0xf7, 0xf3, - 0x89, 0x46, 0xd0, 0x01, 0xc6, 0x83, 0xd7, 0x00, 0x89, 0x76, 0xda, 0x89, - 0x7e, 0xdc, 0x8b, 0x46, 0xd6, 0x8b, 0x56, 0xd8, 0x8b, 0x7e, 0xd0, 0xc4, - 0x5e, 0x5a, 0xe8, 0xac, 0x00, 0xc4, 0x7e, 0x5a, 0xb9, 0x0b, 0x00, 0xbe, - 0xf1, 0x7d, 0x57, 0xf3, 0xa6, 0x5f, 0x26, 0x8b, 0x45, 0x1a, 0x74, 0x0b, - 0x83, 0xc7, 0x20, 0x26, 0x80, 0x3d, 0x00, 0x75, 0xe7, 0x72, 0x68, 0x50, - 0xc4, 0x5e, 0x5a, 0x8b, 0x7e, 0x16, 0x8b, 0x46, 0xd2, 0x8b, 0x56, 0xd4, - 0xe8, 0x7e, 0x00, 0x58, 0x1e, 0x07, 0x8e, 0x5e, 0x5c, 0xbf, 0x00, 0x20, - 0xab, 0x89, 0xc6, 0x01, 0xf6, 0x01, 0xc6, 0xd1, 0xee, 0xad, 0x73, 0x04, - 0xb1, 0x04, 0xd3, 0xe8, 0x80, 0xe4, 0x0f, 0x3d, 0xf8, 0x0f, 0x72, 0xe8, - 0x31, 0xc0, 0xab, 0x0e, 0x1f, 0xc4, 0x5e, 0x5a, 0xbe, 0x00, 0x20, 0xad, - 0x09, 0xc0, 0x75, 0x05, 0x88, 0xd3, 0xff, 0x6e, 0x5a, 0x48, 0x48, 0x8b, - 0x7e, 0x0d, 0x81, 0xe7, 0xff, 0x00, 0xf7, 0xe7, 0x03, 0x46, 0xda, 0x13, - 0x56, 0xdc, 0xe8, 0x34, 0x00, 0xeb, 0xe0, 0x5e, 0xac, 0x56, 0xb4, 0x0e, - 0xcd, 0x10, 0x3c, 0x2e, 0x75, 0xf5, 0xc3, 0xe8, 0xf1, 0xff, 0x45, 0x72, - 0x72, 0x6f, 0x72, 0x21, 0x20, 0x48, 0x69, 0x74, 0x20, 0x61, 0x20, 0x6b, - 0x65, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x72, 0x65, 0x62, 0x6f, 0x6f, 0x74, - 0x2e, 0x30, 0xe4, 0xcd, 0x13, 0xcd, 0x16, 0xcd, 0x19, 0x56, 0x89, 0x46, - 0xc8, 0x89, 0x56, 0xca, 0x8c, 0x46, 0xc6, 0x89, 0x5e, 0xc4, 0xe8, 0xbe, - 0xff, 0x2e, 0xb4, 0x41, 0xbb, 0xaa, 0x55, 0x8a, 0x56, 0x24, 0x84, 0xd2, - 0x74, 0x19, 0xcd, 0x13, 0x72, 0x15, 0xd1, 0xe9, 0x81, 0xdb, 0x54, 0xaa, - 0x75, 0x0d, 0x8d, 0x76, 0xc0, 0x89, 0x5e, 0xcc, 0x89, 0x5e, 0xce, 0xb4, - 0x42, 0xeb, 0x26, 0x8b, 0x4e, 0xc8, 0x8b, 0x56, 0xca, 0x8a, 0x46, 0x18, - 0xf6, 0x66, 0x1a, 0x91, 0xf7, 0xf1, 0x92, 0xf6, 0x76, 0x18, 0x89, 0xd1, - 0x88, 0xc6, 0x86, 0xe9, 0xd0, 0xc9, 0xd0, 0xc9, 0x08, 0xe1, 0x41, 0xc4, - 0x5e, 0xc4, 0xb8, 0x01, 0x02, 0x8a, 0x56, 0x24, 0xcd, 0x13, 0x0f, 0x82, - 0x75, 0xff, 0x8b, 0x46, 0x0b, 0xf6, 0x76, 0xc0, 0x01, 0x46, 0xc6, 0x83, - 0x46, 0xc8, 0x01, 0x83, 0x56, 0xca, 0x00, 0x4f, 0x75, 0x98, 0x8e, 0x46, - 0xc6, 0x5e, 0xc3, 0x4d, 0x45, 0x54, 0x41, 0x4b, 0x45, 0x52, 0x4e, 0x53, - 0x59, 0x53, 0x00, 0x00, 0x55, 0xaa -}; - -static const char fat8_string[8] = { 'F', 'A', 'T', ' ', ' ', ' ', ' ', ' ' }; -static const char fat12_string[8] = { 'F', 'A', 'T', '1', '2', ' ', ' ', ' ' }; -static const char fat16_string[8] = { 'F', 'A', 'T', '1', '6', ' ', ' ', ' ' }; -static const char fat32_string[8] = { 'F', 'A', 'T', '3', '2', ' ', ' ', ' ' }; - - - -static fat_partition_info *fat_get_partition_info(imgtool::partition &partition) -{ - return (fat_partition_info *)partition.extra_bytes(); -} - - - -static imgtoolerr_t fat_read_sector(imgtool::partition &partition, uint32_t sector_index, - int offset, void *buffer, size_t buffer_len) -{ - //const fat_partition_info *disk_info; - imgtoolerr_t err; - uint8_t data[FAT_SECLEN]; - uint32_t block_size; - size_t len; - - //disk_info = fat_get_partition_info(partition); - - /* sanity check */ - err = partition.get_block_size(block_size); - if (err) - return err; - assert(block_size == sizeof(data)); - - while(buffer_len > 0) - { - err = partition.read_block(sector_index++, data); - if (err) - return err; - - len = std::min(buffer_len, sizeof(data) - offset); - memcpy(buffer, data + offset, len); - - buffer = ((uint8_t *) buffer) + len; - buffer_len -= len; - offset = 0; - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_write_sector(imgtool::partition &partition, uint32_t sector_index, - int offset, const void *buffer, size_t buffer_len) -{ - //const fat_partition_info *disk_info; - imgtoolerr_t err; - uint8_t data[FAT_SECLEN]; - const void *write_data; - uint32_t block_size; - size_t len; - - //disk_info = fat_get_partition_info(partition); - - /* sanity check */ - err = partition.get_block_size(block_size); - if (err) - return err; - assert(block_size == sizeof(data)); - - while(buffer_len > 0) - { - len = std::min(buffer_len, sizeof(data) - offset); - - if ((offset != 0) || (buffer_len < sizeof(data))) - { - err = partition.read_block(sector_index, data); - if (err) - return err; - memcpy(data + offset, buffer, len); - write_data = data; - } - else - { - write_data = buffer; - } - - err = partition.write_block(sector_index++, write_data); - if (err) - return err; - - buffer = ((uint8_t *) buffer) + len; - buffer_len -= len; - offset = 0; - } - return IMGTOOLERR_SUCCESS; -} - - -#ifdef UNUSED_FUNCTION -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) -{ - uint8_t header[FAT_SECLEN]; - imgtoolerr_t err; - fat_partition_info *info; - uint32_t fat_bits, total_sectors_l, total_sectors_h, sector_size; - uint64_t available_sectors; - //int has_extended_bios_param_block = true; - - info = fat_get_partition_info(partition); - - /* read the boot/root sector */ - err = fat_read_sector(partition, 0, 0, header, sizeof(header)); - if (err) - return err; - - /* magic bytes present? */ - if ((header[510] != 0x55) || (header[511] != 0xAA)) - return IMGTOOLERR_CORRUPTIMAGE; - - /* determine which type of FAT is on this disk */ - if (!memcmp(&header[54], fat8_string, sizeof(fat8_string))) - fat_bits = 8; - else if (!memcmp(&header[54], fat12_string, sizeof(fat12_string))) - fat_bits = 12; - else if (!memcmp(&header[54], fat16_string, sizeof(fat16_string))) - fat_bits = 16; - else if (!memcmp(&header[54], fat32_string, sizeof(fat32_string))) - fat_bits = 32; - else - { - fat_bits = 8; - //has_extended_bios_param_block = false; - } - - 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); - - if (info->sectors_per_cluster == 0) - return IMGTOOLERR_CORRUPTIMAGE; - - 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; - info->total_clusters = (available_sectors + info->sectors_per_cluster - 1) / info->sectors_per_cluster; - info->cluster_size = FAT_SECLEN * info->sectors_per_cluster; - - if (info->fat_count == 0) - return IMGTOOLERR_CORRUPTIMAGE; - if (sector_size != FAT_SECLEN) - return IMGTOOLERR_CORRUPTIMAGE; - if (info->sectors_per_fat == 0) - return IMGTOOLERR_CORRUPTIMAGE; - if (info->sectors_per_cluster == 0) - return IMGTOOLERR_CORRUPTIMAGE; - if (info->reserved_sectors == 0) - return IMGTOOLERR_CORRUPTIMAGE; - if (info->total_clusters * info->fat_bits > info->sectors_per_fat * FAT_SECLEN * 8) - return IMGTOOLERR_CORRUPTIMAGE; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_partition_create(imgtool::image &image, uint64_t first_block, uint64_t block_count) -{ - imgtoolerr_t err; - uint32_t heads, tracks, sectors_per_track; - uint32_t fat_bits, sectors_per_cluster, reserved_sectors, hidden_sectors; - uint32_t root_dir_count, root_dir_sectors; - uint32_t sectors_per_fat, fat_count, i; - uint32_t boot_sector_offset; - uint64_t total_clusters; - uint8_t media_descriptor; - //const char *title; - const char *fat_bits_string; - uint8_t header[FAT_SECLEN]; -#if 0 - uint64_t first_fat_entries; -#endif - - /* check for limits */ - if (block_count > 0xFFFFFFFFFFFFU) - return IMGTOOLERR_PARAMTOOLARGE; - - /* get the geometry */ - err = image.get_geometry(&tracks, &heads, §ors_per_track); - if (err) - return err; - - /* cap our sector count so that we only use FAT12/16 */ - sectors_per_cluster = (block_count + 65524 - 1) / 65524; - - /* compute the FAT file system type */ - if ((block_count / sectors_per_cluster) <= 4084) - { - fat_bits = 12; - fat_bits_string = fat12_string; - } - else if ((block_count / sectors_per_cluster) <= 65524) - { - fat_bits = 16; - fat_bits_string = fat16_string; - } - else - { - fat_bits = 32; - fat_bits_string = fat32_string; - } - - /* figure out media type */ - i = 0; - while((known_media[i].heads > 0) && ((known_media[i].heads != heads) - || (known_media[i].tracks != tracks) - || (known_media[i].sectors != sectors_per_track))) - { - i++; - } - media_descriptor = known_media[i].media_descriptor; - - /* other miscellaneous settings */ - //title = ""; - fat_count = 2; - root_dir_count = 512; - hidden_sectors = 0; - reserved_sectors = 1; - - /* calculated settings */ - root_dir_sectors = (root_dir_count * FAT_DIRENT_SIZE + FAT_SECLEN - 1) / FAT_SECLEN; - total_clusters = (block_count - reserved_sectors - hidden_sectors - root_dir_sectors) - / sectors_per_cluster; - sectors_per_fat = (total_clusters * fat_bits + (FAT_SECLEN * 8) - 1) - / (FAT_SECLEN * 8); - - /* 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()); - memcpy(&header[43], " ", 11); - memcpy(&header[54], fat_bits_string, 8); - - /* store boot code */ - boot_sector_offset = sizeof(header) - sizeof(boot_sector_code); - if (boot_sector_offset < 62) - return IMGTOOLERR_UNEXPECTED; /* sanity check */ - if (boot_sector_offset > 510) - return IMGTOOLERR_UNEXPECTED; /* sanity check */ - memcpy(&header[boot_sector_offset], boot_sector_code, sizeof(boot_sector_code)); - - /* specify jump instruction */ - if (boot_sector_offset <= 129) - { - header[0] = 0xEB; /* JMP rel8 */ - 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) */ - } - - err = image.write_block(first_block, header); - if (err) - return err; - - /* clear out file allocation table */ - for (i = reserved_sectors; i < (reserved_sectors + sectors_per_fat * fat_count + root_dir_sectors); i++) - { - err = image.clear_block(first_block + i, 0); - if (err) - return err; - } - - // 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 = little_endianize_int64(first_fat_entries); - - for (i = 0; i < fat_count; i++) - { - err = image->write_block(first_block + 1 + (i * sectors_per_fat), &first_fat_entries); - if (err) - return err; - } -#endif - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_load_fat(imgtool::partition &partition, uint8_t **fat_table) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - const fat_partition_info *disk_info; - uint8_t *table; - uint32_t table_size; - uint32_t pos, len; - uint32_t sector_index; - - disk_info = fat_get_partition_info(partition); - - table_size = disk_info->sectors_per_fat * disk_info->fat_count * FAT_SECLEN; - - /* allocate the table with extra bytes, in case we "overextend" our reads */ - table = (uint8_t*)malloc(table_size + sizeof(uint64_t)); - if (!table) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto done; - } - memset(table, 0, table_size + sizeof(uint64_t)); - - pos = 0; - sector_index = disk_info->reserved_sectors; - - while(pos < table_size) - { - len = std::min(table_size - pos, uint32_t(FAT_SECLEN)); - - err = fat_read_sector(partition, sector_index++, 0, &table[pos], len); - if (err) - goto done; - - pos += FAT_SECLEN; - } - -done: - if (err && table) - { - free(table); - table = NULL; - } - *fat_table = table; - return err; -} - - - -static imgtoolerr_t fat_save_fat(imgtool::partition &partition, const uint8_t *fat_table) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - const fat_partition_info *disk_info; - uint32_t table_size; - uint32_t pos, len; - uint32_t sector_index; - - disk_info = fat_get_partition_info(partition); - - table_size = disk_info->sectors_per_fat * disk_info->fat_count * FAT_SECLEN; - - pos = 0; - sector_index = disk_info->reserved_sectors; - - while(pos < table_size) - { - len = std::min(table_size - pos, uint32_t(FAT_SECLEN)); - - err = fat_write_sector(partition, sector_index++, 0, &fat_table[pos], len); - if (err) - goto done; - - pos += FAT_SECLEN; - } - -done: - return err; -} - - - -static uint32_t fat_get_fat_entry(imgtool::partition &partition, const uint8_t *fat_table, uint32_t fat_entry) -{ - const fat_partition_info *disk_info; - uint64_t entry; - uint32_t bit_index, i; - uint32_t last_entry = 0; - uint32_t bit_mask; - - disk_info = fat_get_partition_info(partition); - bit_index = fat_entry * disk_info->fat_bits; - bit_mask = 0xFFFFFFFF >> (32 - disk_info->fat_bits); - - if (fat_entry >= disk_info->total_clusters) - { - assert(0); - return 1; - } - - /* make sure that the cluster is free in all fats */ - for (i = 0; i < disk_info->fat_count; i++) - { - memcpy(&entry, fat_table + (i * FAT_SECLEN - * disk_info->sectors_per_fat) + (bit_index / 8), sizeof(entry)); - - /* we've extracted the bytes; we now need to normalize it */ - entry = little_endianize_int64(entry); - entry >>= bit_index % 8; - entry &= bit_mask; - - if (i == 0) - last_entry = (uint32_t) entry; - else if (last_entry != (uint32_t) entry) - return 1; /* if the FATs disagree; mark this as reserved */ - } - - /* normalize special clusters */ - if (last_entry >= (0xFFFFFFF0 & bit_mask)) - { - last_entry |= 0xFFFFFFF0; - if (last_entry >= 0xFFFFFFF8) - last_entry = 0xFFFFFFFF; - } - return last_entry; -} - - - -static void fat_set_fat_entry(imgtool::partition &partition, uint8_t *fat_table, uint32_t fat_entry, uint32_t value) -{ - const fat_partition_info *disk_info; - uint64_t entry; - uint32_t bit_index, i; - - disk_info = fat_get_partition_info(partition); - bit_index = fat_entry * disk_info->fat_bits; - value &= 0xFFFFFFFF >> (32 - disk_info->fat_bits); - - for (i = 0; i < disk_info->fat_count; i++) - { - memcpy(&entry, fat_table + (i * FAT_SECLEN - * 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 = little_endianize_int64(entry); - - memcpy(fat_table + (i * FAT_SECLEN - * disk_info->sectors_per_fat) + (bit_index / 8), &entry, sizeof(entry)); - } -} - - - -static void fat_debug_integrity_check(imgtool::partition &partition, const uint8_t *fat_table, const fat_file *file) -{ -#ifdef MAME_DEBUG - /* debug function to test the integrity of a file */ - uint32_t cluster; - const fat_partition_info *disk_info; - - disk_info = fat_get_partition_info(partition); - cluster = file->first_cluster ? file->first_cluster : 0xFFFFFFFF; - - if (!file->root) - { - while(cluster != 0xFFFFFFFF) - { - assert((cluster >= 2) && (cluster < disk_info->total_clusters)); - cluster = fat_get_fat_entry(partition, fat_table, cluster); - } - } -#endif -} - - - -static imgtoolerr_t fat_seek_file(imgtool::partition &partition, fat_file *file, uint32_t pos) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - const fat_partition_info *disk_info; - uint32_t new_cluster; - uint8_t *fat_table = NULL; - - disk_info = fat_get_partition_info(partition); - - /* can't seek past end of file */ - if (!file->directory && (pos > file->filesize)) - pos = file->filesize; - - if (file->first_cluster == 0) - { - /* special case; the root directory */ - file->index = pos; - } - else - { - /* first, we need to check to see if we have to go back to the beginning */ - if (pos < file->index) - { - file->cluster = file->first_cluster; - file->cluster_index = 0; - file->eof = 0; - } - - /* skip ahead clusters */ - while((file->cluster_index + disk_info->cluster_size) <= pos) - { - if (!fat_table) - { - err = fat_load_fat(partition, &fat_table); - if (err) - goto done; - } - - new_cluster = fat_get_fat_entry(partition, fat_table, file->cluster); - - file->cluster = new_cluster; - file->cluster_index += disk_info->cluster_size; - - /* are we at the end of the file? */ - if (new_cluster == 0xFFFFFFFF) - { - pos = file->cluster_index; - file->eof = 1; - } - } - file->index = pos; - } - -done: - if (fat_table) - free(fat_table); - return err; -} - - - -static uint32_t fat_get_filepos_sector_index(imgtool::partition &partition, fat_file *file) -{ - uint32_t sector_index; - const fat_partition_info *disk_info; - - disk_info = fat_get_partition_info(partition); - - sector_index = disk_info->reserved_sectors + (disk_info->sectors_per_fat * disk_info->fat_count); - if (file->root) - { - /* special case for the root file */ - sector_index += file->index / FAT_SECLEN; - } - else - { - /* cluster out of range? */ - if ((file->cluster < 2) || (file->cluster >= disk_info->total_clusters)) - return 0; - - sector_index += (disk_info->root_entries * FAT_DIRENT_SIZE + FAT_SECLEN - 1) / FAT_SECLEN; - sector_index += (file->cluster - 2) * disk_info->sectors_per_cluster; - sector_index += (file->index / FAT_SECLEN) % disk_info->sectors_per_cluster; - } - return sector_index; -} - - - -static imgtoolerr_t fat_corrupt_file_error(const fat_file *file) -{ - imgtoolerr_t err; - if (file->root) - err = IMGTOOLERR_CORRUPTIMAGE; - else if (file->directory) - err = IMGTOOLERR_CORRUPTDIR; - else - err = IMGTOOLERR_CORRUPTFILE; - return err; -} - - - -static imgtoolerr_t fat_readwrite_file(imgtool::partition &partition, fat_file *file, - void *buffer, size_t buffer_len, size_t *bytes_read, int read_or_write) -{ - imgtoolerr_t err; -// const fat_partition_info *disk_info; - uint32_t sector_index; - int offset; - size_t len; - -// disk_info = - fat_get_partition_info(partition); - if (bytes_read) - *bytes_read = 0; - if (!file->directory) - buffer_len = std::min(buffer_len, size_t(file->filesize - file->index)); - - while(!file->eof && (buffer_len > 0)) - { - sector_index = fat_get_filepos_sector_index(partition, file); - if (sector_index == 0) - return fat_corrupt_file_error(file); - - offset = file->index % FAT_SECLEN; - len = std::min(buffer_len, size_t(FAT_SECLEN - offset)); - - /* read or write the data from the disk */ - if (read_or_write) - err = fat_write_sector(partition, sector_index, offset, buffer, len); - else - err = fat_read_sector(partition, sector_index, offset, buffer, len); - if (err) - return err; - - /* and move the file pointer ahead */ - err = fat_seek_file(partition, file, file->index + len); - if (err) - return err; - - buffer = ((uint8_t *) buffer) + len; - buffer_len -= len; - if (bytes_read) - *bytes_read += len; - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_read_file(imgtool::partition &partition, fat_file *file, - void *buffer, size_t buffer_len, size_t *bytes_read) -{ - return fat_readwrite_file(partition, file, buffer, buffer_len, bytes_read, 0); -} - - - -static imgtoolerr_t fat_write_file(imgtool::partition &partition, fat_file *file, - const void *buffer, size_t buffer_len, size_t *bytes_read) -{ - return fat_readwrite_file(partition, file, (void *) buffer, buffer_len, bytes_read, 1); -} - - - -static uint32_t fat_allocate_cluster(imgtool::partition &partition, uint8_t *fat_table) -{ - const fat_partition_info *disk_info; - uint32_t i, val; - - disk_info = fat_get_partition_info(partition); - - for (i = 2; i < disk_info->total_clusters; i++) - { - val = fat_get_fat_entry(partition, fat_table, i); - if (val == 0) - { - fat_set_fat_entry(partition, fat_table, i, 1); - return i; - } - } - return 0; -} - - - -/* sets the size of a file; ~0 means 'delete' */ -static imgtoolerr_t fat_set_file_size(imgtool::partition &partition, fat_file *file, - uint32_t new_size) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - const fat_partition_info *disk_info; - uint32_t new_cluster_count; - uint32_t old_cluster_count; - uint32_t cluster, write_cluster, last_cluster, new_pos, i; - uint8_t *fat_table = NULL; - uint8_t dirent[32]; - size_t clear_size; - void *clear_buffer = NULL; - int delete_file = false; - int rest_free = false; - - disk_info = fat_get_partition_info(partition); - - LOG(("fat_set_file_size(): file->first_cluster=%d new_size=0x%08x\n", file->first_cluster, new_size)); - - /* special case */ - if (new_size == ~0) - { - delete_file = true; - new_size = 0; - } - - /* if this is the trivial case (not changing the size), succeed */ - if (!delete_file && (file->filesize == new_size)) - { - err = IMGTOOLERR_SUCCESS; - goto done; - } - - /* what is the new position? */ - new_pos = std::min(file->index, new_size); - - if (file->root) - { - /* this is the root directory; this is a special case */ - if (new_size > (disk_info->root_entries * FAT_DIRENT_SIZE)) - { - err = IMGTOOLERR_NOSPACE; - goto done; - } - } - else - { - old_cluster_count = (file->filesize + disk_info->cluster_size - 1) / disk_info->cluster_size; - new_cluster_count = (new_size + disk_info->cluster_size - 1) / disk_info->cluster_size; - cluster = 0; - - /* load the dirent */ - err = fat_read_sector(partition, file->dirent_sector_index, file->dirent_sector_offset, dirent, sizeof(dirent)); - if (err) - goto done; - - /* need to load the FAT whether we are growing or shrinking the file */ - if (old_cluster_count != new_cluster_count) - { - err = fat_load_fat(partition, &fat_table); - if (err) - goto done; - - cluster = 0; - i = 0; - do - { - last_cluster = cluster; - write_cluster = 0; - - /* identify the next cluster */ - if (cluster != 0) - cluster = fat_get_fat_entry(partition, fat_table, cluster); - else - cluster = file->first_cluster ? file->first_cluster : 0xFFFFFFFF; - - /* do we need to grow the file by a cluster? */ - if (i < new_cluster_count && ((cluster < 2) || (cluster >= disk_info->total_clusters))) - { - /* grow this file by a cluster */ - cluster = fat_allocate_cluster(partition, fat_table); - if (cluster == 0) - { - err = IMGTOOLERR_NOSPACE; - goto done; - } - - write_cluster = cluster; - } - else if (i >= new_cluster_count) - { - /* we are shrinking the file; we need to unlink this node */ - if ((cluster < 2) || (cluster >= disk_info->total_clusters)) - cluster = 0xFFFFFFFF; /* ack file is corrupt! recover */ - write_cluster = 0xFFFFFFFF; - } - - /* write out the entry, if appropriate */ - if (write_cluster != 0) - { - /* are we tieing up loose ends? */ - if (rest_free && (write_cluster == 0xFFFFFFFF)) - write_cluster = 0; - - if (last_cluster == 0) - file->first_cluster = (write_cluster != 0xFFFFFFFF) ? write_cluster : 0; - else - fat_set_fat_entry(partition, fat_table, last_cluster, write_cluster); - - /* did we write the last cluster? if so, the rest (if any) are free */ - if (write_cluster == 0xFFFFFFFF) - rest_free = true; - } - } - while((++i < new_cluster_count) || (cluster != 0xFFFFFFFF)); - } - - /* record the new file size */ - place_integer_le(dirent, 26, 2, file->first_cluster); - place_integer_le(dirent, 28, 4, new_size); - - /* delete the file, if appropriate */ - if (delete_file) - dirent[0] = 0xE5; - - /* save the dirent */ - err = fat_write_sector(partition, file->dirent_sector_index, file->dirent_sector_offset, dirent, sizeof(dirent)); - if (err) - goto done; - - /* if we've modified the FAT, save it out */ - if (fat_table) - { - err = fat_save_fat(partition, fat_table); - if (err) - goto done; - } - - /* update the file structure */ - if (!file->directory) - file->filesize = new_size; - file->cluster = file->first_cluster; - file->index = 0; - file->cluster_index = 0; - file->eof = (new_cluster_count == 0); - } - - /* special case; clear out stale bytes on non-root directories */ - if (file->directory && !delete_file) - { - if (file->root) - clear_size = std::min(file->filesize - new_size, uint32_t(FAT_DIRENT_SIZE)); - else - clear_size = (disk_info->cluster_size - (new_size % disk_info->cluster_size)) % disk_info->cluster_size; - - if (clear_size > 0) - { - err = fat_seek_file(partition, file, new_size); - if (err) - goto done; - - clear_buffer = malloc(clear_size); - if (!clear_buffer) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto done; - } - memset(clear_buffer, '\0', clear_size); - - err = fat_write_file(partition, file, clear_buffer, clear_size, NULL); - if (err) - goto done; - } - } - - /* seek back to original pos */ - err = fat_seek_file(partition, file, new_pos); - if (err) - goto done; - - if (fat_table) - fat_debug_integrity_check(partition, fat_table, file); - -done: - if (fat_table) - free(fat_table); - if (clear_buffer) - free(clear_buffer); - return err; -} - - - -static void prepend_lfn_bytes(char16_t *lfn_buf, size_t lfn_buflen, size_t *lfn_len, - const uint8_t *entry, int offset, int chars) -{ - uint16_t w; - int i; - size_t move_len; - - move_len = std::min(*lfn_len + 1, lfn_buflen - chars - 1); - memmove(&lfn_buf[chars], &lfn_buf[0], move_len * sizeof(*lfn_buf)); - - for (i = 0; i < chars; i++) - { - /* read the character */ - memcpy(&w, &entry[offset + i * 2], 2); - w = little_endianize_int16(w); - - /* append to buffer */ - lfn_buf[i] = (w != 0xFFFF) ? w : 0; - } - *lfn_len += chars; -} - - - -static uint8_t fat_calc_filename_checksum(const uint8_t *short_filename) -{ - uint8_t checksum; - int i, j; - - checksum = 0; - for (i = 0; i < 11; i++) - { - j = checksum & 1; - checksum >>= 1; - if (j) - checksum |= 0x80; - checksum += short_filename[i]; - } - return checksum; -} - - - -static void fat_calc_dirent_lfnchecksum(uint8_t *entry, size_t entry_len) -{ - uint8_t checksum; - int i; - - checksum = fat_calc_filename_checksum(entry + entry_len - FAT_DIRENT_SIZE); - - for (i = 0; i < (entry_len / FAT_DIRENT_SIZE - 1); i++) - entry[i * FAT_DIRENT_SIZE + 13] = checksum; -} - - - -static char fat_canonicalize_sfn_char(char ch) -{ - /* return the display version of this short file name character */ - return tolower(ch); -} - - - -static void fat_canonicalize_sfn(char *sfn, const uint8_t *sfn_bytes) -{ - /* return the display version of this short file name */ - int i; - - memset(sfn, '\0', 13); - memcpy(sfn, sfn_bytes, 8); - rtrim(sfn); - if (sfn[0] == 0x05) - sfn[0] = (char) 0xE5; - if ((sfn_bytes[8] != ' ') || (sfn_bytes[9] != ' ') || (sfn_bytes[10] != ' ')) - { - strcat(sfn, "."); - memcpy(sfn + strlen(sfn), &sfn_bytes[8], 3); - rtrim(sfn); - } - for (i = 0; sfn[i]; i++) - sfn[i] = fat_canonicalize_sfn_char(sfn[i]); -} - - - -static imgtool::datetime fat_crack_time(uint32_t fat_time) -{ - util::arbitrary_datetime dt; - dt.second = ((fat_time >> 0) & 0x001F) * 2; - dt.minute = ((fat_time >> 5) & 0x003F); - dt.hour = ((fat_time >> 11) & 0x001F); - dt.day_of_month = ((fat_time >> 16) & 0x001F); - dt.month = ((fat_time >> 21) & 0x000F); - dt.year = ((fat_time >> 25) & 0x007F) + 1980; - return imgtool::datetime(imgtool::datetime::LOCAL, dt); -} - - - -static uint32_t fat_setup_time(time_t ansi_time) -{ - std::tm t = *localtime(&ansi_time); - - uint32_t result = 0; - result |= (((uint32_t) (t.tm_sec / 2)) & 0x001F) << 0; - result |= (((uint32_t) t.tm_min) & 0x003F) << 5; - result |= (((uint32_t) t.tm_hour) & 0x001F) << 11; - result |= (((uint32_t) t.tm_mday) & 0x001F) << 16; - result |= (((uint32_t) t.tm_mon) & 0x000F) << 21; - result |= (((uint32_t) (t.tm_year + 1900 - 1980)) & 0x007F) << 25; - - return result; -} - - - -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; - uint8_t lfn_checksum = 0; - uint32_t entry_index, entry_sector_index, entry_sector_offset; - - assert(file->directory); - lfn_buf[0] = '\0'; - memset(&ent, 0, sizeof(ent)); - //disk_info = fat_get_partition_info(partition); - - /* The first eight bytes of a FAT directory entry is a blank padded name - * - * The first byte can be special: - * 0x00 - entry is available and no further entry is used - * 0x05 - first character is actually 0xe5 - * 0x2E - dot entry; either '.' or '..' - * 0xE5 - entry has been erased and is available - * - * Byte 11 is the attributes; and 0x0F denotes a LFN entry - */ - do - { - entry_index = file->index; - entry_sector_index = fat_get_filepos_sector_index(partition, file); - entry_sector_offset = file->index % FAT_SECLEN; - - err = fat_read_file(partition, file, entry, sizeof(entry), &bytes_read); - if (err) - return err; - if (bytes_read < sizeof(entry)) - memset(entry, 0, sizeof(entry)); - - if (entry[11] == 0x0F) - { - /* this is an LFN entry */ - if ((lfn_lastentry == 0) - || ((entry[0] & 0x3F) != (lfn_lastentry - 1)) - || (lfn_checksum != entry[13])) - { - lfn_buf[0] = 0; - lfn_len = 0; - lfn_checksum = entry[13]; - } - lfn_lastentry = entry[0] & 0x3F; - prepend_lfn_bytes(lfn_buf, std::size(lfn_buf), - &lfn_len, entry, 28, 2); - prepend_lfn_bytes(lfn_buf, std::size(lfn_buf), - &lfn_len, entry, 14, 6); - prepend_lfn_bytes(lfn_buf, std::size(lfn_buf), - &lfn_len, entry, 1, 5); - } - else if (freeent && (freeent->position == ~0)) - { - /* do a quick check to find out if we found space */ - if ((entry[0] == '\0') || (entry[0] == 0xE5)) - { - if (freeent->candidate_position > entry_index) - freeent->candidate_position = entry_index; - - if ((entry[0] == '\0') || (freeent->candidate_position + freeent->required_size < file->index)) - freeent->position = freeent->candidate_position; - } - else - { - freeent->candidate_position = ~0; - } - } - } - while((entry[0] == 0x2E) || (entry[0] == 0xE5) || (entry[11] == 0x0F)); - - /* no more directory entries? */ - if (entry[0] == '\0') - { - ent.eof = 1; - return IMGTOOLERR_SUCCESS; - } - - /* pick apart short filename */ - fat_canonicalize_sfn(ent.short_filename, entry); - - /* and the long filename */ - if (lfn_lastentry == 1) - { - /* only use the LFN if the checksum passes */ - if (lfn_checksum == fat_calc_filename_checksum(entry)) - { - i = 0; - j = 0; - do - { - i += uchar_from_utf16(&ch, &lfn_buf[i], std::size(lfn_buf) - i); - j += utf8_from_uchar(&ent.long_filename[j], std::size(ent.long_filename) - j, ch); - } - while(ch != 0); - } - } - - /* other attributes */ - ent.filesize = pick_integer_le(entry, 28, 4); - ent.directory = (entry[11] & 0x10) ? 1 : 0; - ent.first_cluster = pick_integer_le(entry, 26, 2); - 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)); - return IMGTOOLERR_SUCCESS; -} - - - -enum sfn_disposition_t -{ - SFN_SUFFICIENT, /* name fully representable in short file name */ - SFN_DERIVATIVE, /* name not fully representable in short file name, but no need to tildize */ - SFN_MANGLED /* name not representable in short file name; must tildize */ -}; - -static imgtoolerr_t fat_construct_dirent(const char *filename, creation_policy_t create, - uint8_t **entry, size_t *entry_len) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - uint8_t *created_entry = NULL; - uint8_t *new_created_entry; - uint32_t now; - size_t created_entry_len = FAT_DIRENT_SIZE; - size_t created_entry_pos = 0; - char32_t ch; - char last_short_char = ' '; - char short_char = '\0'; - char canonical_short_char; - char16_t buf[UTF16_CHAR_MAX]; - int i, len; - int sfn_pos = 0; - sfn_disposition_t sfn_disposition = SFN_SUFFICIENT; - int sfn_in_extension = 0; - - /* sanity check */ - if (*filename == '\0') - { - err = IMGTOOLERR_BADFILENAME; - goto done; - } - - /* construct intial entry */ - created_entry = (uint8_t *) malloc(FAT_DIRENT_SIZE); - if (!created_entry) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto done; - } - - /* set up the basics for the new dirent */ - memset(created_entry + 0, ' ', 11); - memset(created_entry + 12, '\0', FAT_DIRENT_SIZE - 12); - created_entry[11] = (create == CREATE_DIR) ? 0x10 : 0x00; - - /* 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); - - while(*filename) - { - filename += uchar_from_utf8(&ch, filename, UTF8_CHAR_MAX); - - /* 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 - short_char = '\0'; /* illegal SFN char */ - 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)) - sfn_disposition = std::max(sfn_disposition, SFN_DERIVATIVE); - else - sfn_disposition = SFN_MANGLED; - } - - /* append the short filename char */ - if (short_char == '.') - { - /* multiple extensions or trailing spaces? */ - if (sfn_in_extension) - sfn_disposition = SFN_MANGLED; - else if (last_short_char == ' ') - sfn_disposition = std::max(sfn_disposition, SFN_DERIVATIVE); - - sfn_in_extension = 1; - sfn_pos = 8; - created_entry[created_entry_len - FAT_DIRENT_SIZE + 8] = ' '; - created_entry[created_entry_len - FAT_DIRENT_SIZE + 9] = ' '; - created_entry[created_entry_len - FAT_DIRENT_SIZE + 10] = ' '; - } - else if (sfn_pos == (sfn_in_extension ? 11 : 8)) - { - /* ran out of characters for short filename */ - sfn_disposition = SFN_MANGLED; - } - else if (short_char != '\0') - { - created_entry[created_entry_len - FAT_DIRENT_SIZE + sfn_pos++] = short_char; - } - last_short_char = short_char; - - - /* convert to UTF-16 and add a long filename entry */ - len = utf16le_from_uchar(buf, UTF16_CHAR_MAX, ch); - for (i = 0; i < len; i++) - { - switch(created_entry_pos) - { - case 0: - case 32: - /* need to grow */ - new_created_entry = (uint8_t *) malloc(created_entry_len + FAT_DIRENT_SIZE); - if (!new_created_entry) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto done; - } - - /* move existing entries forward */ - memmove(new_created_entry + 32, created_entry, created_entry_len); - - if (created_entry) free(created_entry); - created_entry = new_created_entry; - created_entry_len += 32; - - /* set up this LFN */ - memset(created_entry, '\0', 32); - memset(&created_entry[1], '\xFF', 10); - memset(&created_entry[14], '\xFF', 12); - memset(&created_entry[28], '\xFF', 4); - created_entry[11] = 0x0F; - - /* specify entry index */ - created_entry[0] = (created_entry_len / 32) - 1; - if (created_entry[0] >= 0x40) - { - err = IMGTOOLERR_BADFILENAME; - goto done; - } - created_entry_pos = 1; - break; - - case 11: - created_entry_pos = 14; - break; - - case 26: - created_entry_pos = 28; - break; - } - - memcpy(&created_entry[created_entry_pos], &buf[i], 2); - created_entry_pos += 2; - } - } - - /* trailing spaces? */ - if (short_char == ' ') - sfn_disposition = std::max(sfn_disposition, SFN_DERIVATIVE); - - if (sfn_disposition == SFN_SUFFICIENT) - { - /* the short filename suffices; remove the LFN stuff */ - memcpy(created_entry, created_entry + created_entry_len - FAT_DIRENT_SIZE, FAT_DIRENT_SIZE); - created_entry_len = FAT_DIRENT_SIZE; - free(created_entry); - created_entry = NULL; - new_created_entry = (uint8_t *) malloc(created_entry_len); - if (!new_created_entry) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto done; - } - created_entry = new_created_entry; - } - else - { - /* need to do finishing touches on the LFN */ - created_entry[0] |= 0x40; - - /* if necessary, mangle the name */ - if (sfn_disposition == SFN_MANGLED) - { - i = 6; - while((i > 0) && isspace(created_entry[created_entry_len - FAT_DIRENT_SIZE + i - 1])) - i--; - created_entry[created_entry_len - FAT_DIRENT_SIZE + i + 0] = '~'; - created_entry[created_entry_len - FAT_DIRENT_SIZE + i + 1] = '1'; - } - fat_calc_dirent_lfnchecksum(created_entry, created_entry_len); - } - -done: - if (err && created_entry) - { - free(created_entry); - created_entry = NULL; - } - *entry = created_entry; - *entry_len = created_entry_len; - return err; -} - - - -static void fat_bump_dirent(imgtool::partition &partition, uint8_t *entry, size_t entry_len) -{ - uint8_t *sfn_entry; - int pos, digit_count, i; - uint32_t digit_place, val = 0; - - sfn_entry = &entry[entry_len - FAT_DIRENT_SIZE]; - - digit_place = 1; - for (pos = 7; (pos >= 0) && isdigit((char) sfn_entry[pos]); pos--) - { - val += (sfn_entry[pos] - '0') * digit_place; - digit_place *= 10; - } - val++; - pos++; - - /* count the digits */ - digit_place = 1; - digit_count = 1; - while(val >= digit_place * 10) - { - digit_count++; - digit_place *= 10; - } - - /* give us some more space, if necessary */ - while ((pos > 0) && ((pos + digit_count) > 8)) - pos--; - - /* have we actually ran out of digits */ - if ((pos + digit_count) > 8) - { - /* extreme degenerate case; simply randomize the filename */ - for (i = 0; i < 6; i++) - sfn_entry[i] = 'A' + (std::rand() % 26); - sfn_entry[6] = '~'; - sfn_entry[7] = '0'; - } - else - { - /* write the tilde, if possible */ - if (pos > 0) - sfn_entry[pos - 1] = '~'; - - /* write out the number */ - while(digit_place > 0) - { - sfn_entry[pos++] = (val / digit_place) + '0'; - val %= digit_place; - digit_place /= 10; - } - } - - /* since we changed the short file name, we need to recalc the checksums - * in the LFN entries */ - fat_calc_dirent_lfnchecksum(entry, entry_len); -} - - - -static imgtoolerr_t fat_lookup_path(imgtool::partition &partition, const char *path, - creation_policy_t create, fat_file *file) -{ - imgtoolerr_t err; - const fat_partition_info *disk_info; - fat_dirent ent; - fat_freeentry_info freeent = { 0, }; - const char *next_path_part; - uint8_t *created_entry = NULL; - size_t created_entry_len = 0; - uint32_t entry_sector_index, entry_sector_offset; - uint32_t parent_first_cluster; - int bumped_sfn; - char sfn[13]; - - disk_info = fat_get_partition_info(partition); - - memset(file, 0, sizeof(*file)); - file->root = 1; - file->directory = 1; - file->filesize = disk_info->root_entries * FAT_DIRENT_SIZE; - - while(*path) - { - if (!file->directory) - { - err = IMGTOOLERR_PATHNOTFOUND; - goto done; - } - - next_path_part = path + strlen(path) + 1; - if (create && (*next_path_part == '\0')) - { - /* this is the last entry, and we are creating a file */ - err = fat_construct_dirent(path, create, &created_entry, &created_entry_len); - if (err) - goto done; - - freeent.required_size = created_entry_len; - freeent.candidate_position = ~0; - freeent.position = ~0; - } - - do - { - err = fat_read_dirent(partition, file, ent, created_entry ? &freeent : NULL); - if (err) - goto done; - - LOG(("fat_lookup_path(): %s/%s: %d\n", ent.short_filename, ent.long_filename, ent.dirent_sector_offset)); - } - while(!ent.eof && core_stricmp(path, ent.short_filename) && core_stricmp(path, ent.long_filename)); - - parent_first_cluster = file->first_cluster; - - if (ent.eof) - { - /* it seems that we have reached the end of this directory */ - if (!created_entry) - { - err = IMGTOOLERR_FILENOTFOUND; - goto done; - } - - if (created_entry_len > FAT_DIRENT_SIZE) - { - /* must ensure uniqueness of the short filename */ - do - { - /* rewind to the beginning of the directory */ - err = fat_seek_file(partition, file, 0); - if (err) - goto done; - - bumped_sfn = false; - fat_canonicalize_sfn(sfn, &created_entry[created_entry_len - FAT_DIRENT_SIZE]); - - do - { - err = fat_read_dirent(partition, file, ent, NULL); - if (err) - goto done; - - if (!core_stricmp(sfn, ent.short_filename)) - { - bumped_sfn = true; - fat_bump_dirent(partition, created_entry, created_entry_len); - fat_canonicalize_sfn(sfn, &created_entry[created_entry_len - FAT_DIRENT_SIZE]); - } - } - while(!ent.eof); - } - while(bumped_sfn); - } - - LOG(("fat_lookup_path(): creating entry; pos=%u length=%u\n", freeent.position, freeent.required_size)); - - err = fat_set_file_size(partition, file, std::max(file->filesize, uint32_t(freeent.position + created_entry_len))); - if (err) - goto done; - - err = fat_seek_file(partition, file, freeent.position); - if (err) - goto done; - - err = fat_write_file(partition, file, created_entry, created_entry_len, NULL); - if (err) - goto done; - - /* we have to do a special seek operation to get the main dirent */ - err = fat_seek_file(partition, file, freeent.position + created_entry_len - FAT_DIRENT_SIZE); - if (err) - goto done; - entry_sector_index = fat_get_filepos_sector_index(partition, file); - entry_sector_offset = file->index % FAT_SECLEN; - - /* build the file struct for the newly created file/directory */ - memset(file, 0, sizeof(*file)); - file->directory = (created_entry[created_entry_len - FAT_DIRENT_SIZE + 11] & 0x10) ? 1 : 0; - file->dirent_sector_index = entry_sector_index; - file->dirent_sector_offset = entry_sector_offset; - } - else - { - /* update the current file */ - memset(file, 0, sizeof(*file)); - file->directory = ent.directory; - file->filesize = ent.filesize; - file->cluster = ent.first_cluster; - file->first_cluster = ent.first_cluster; - file->dirent_sector_index = ent.dirent_sector_index; - file->dirent_sector_offset = ent.dirent_sector_offset; - } - - path = next_path_part; - file->parent_first_cluster = parent_first_cluster; - } - - err = IMGTOOLERR_SUCCESS; - -done: - if (created_entry) - free(created_entry); - return err; -} - - - -static imgtoolerr_t fat_partition_beginenum(imgtool::directory &enumeration, const char *path) -{ - imgtoolerr_t err; - fat_file *file; - - file = (fat_file *) enumeration.extra_bytes(); - - err = fat_lookup_path(enumeration.partition(), path, CREATE_NONE, file); - if (err) - return err; - if (!file->directory) - return IMGTOOLERR_PATHNOTFOUND; - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_partition_nextenum(imgtool::directory &enumeration, imgtool_dirent &ent) -{ - imgtoolerr_t err; - fat_file *file; - fat_dirent fatent; - - file = (fat_file *) enumeration.extra_bytes(); - err = fat_read_dirent(enumeration.partition(), file, fatent, NULL); - if (err) - return err; - - /* copy stuff from the FAT dirent to the Imgtool dirent */ - 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; - ent.eof = fatent.eof; - ent.creation_time = fatent.creation_time; - ent.lastmodified_time = fatent.lastmodified_time; - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_read_bootblock(imgtool::partition &partition, imgtool::stream &stream) -{ - imgtoolerr_t err; - uint8_t block[FAT_SECLEN]; - - err = fat_read_sector(partition, 0, 0, block, sizeof(block)); - if (err) - return err; - - stream.write(block, sizeof(block)); - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_write_bootblock(imgtool::partition &partition, imgtool::stream &stream) -{ - imgtoolerr_t err; - uint8_t block[FAT_SECLEN]; - uint8_t new_block[FAT_SECLEN]; - - if (stream.size() != sizeof(new_block)) - return IMGTOOLERR_UNEXPECTED; - stream.read(new_block, sizeof(new_block)); - - if (new_block[510] != 0x55) - return IMGTOOLERR_UNEXPECTED; - if (new_block[511] != 0xAA) - return IMGTOOLERR_UNEXPECTED; - - /* read current boot sector */ - err = fat_read_sector(partition, 0, 0, block, sizeof(block)); - if (err) - return err; - - /* merge in the new stuff */ - memcpy(&block[ 0], &new_block[ 0], 3); - memcpy(&block[62], &new_block[62], 448); - - /* and write it out */ - err = fat_write_sector(partition, 0, 0, block, sizeof(block)); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_partition_readfile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &destf) -{ - imgtoolerr_t err; - fat_file file; - size_t bytes_read; - char buffer[1024]; - - /* special case for bootblock */ - if (filename == FILENAME_BOOTBLOCK) - return fat_read_bootblock(partition, destf); - - err = fat_lookup_path(partition, filename, CREATE_NONE, &file); - if (err) - return err; - - if (file.directory) - return IMGTOOLERR_FILENOTFOUND; - - do - { - err = fat_read_file(partition, &file, buffer, sizeof(buffer), &bytes_read); - if (err) - return err; - - destf.write(buffer, bytes_read); - } - while(bytes_read > 0); - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_partition_writefile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &sourcef, util::option_resolution *opts) -{ - imgtoolerr_t err; - fat_file file; - uint32_t bytes_left, len; - char buffer[1024]; - - /* special case for bootblock */ - if (filename == FILENAME_BOOTBLOCK) - return fat_write_bootblock(partition, sourcef); - - err = fat_lookup_path(partition, filename, CREATE_FILE, &file); - if (err) - return err; - - if (file.directory) - return IMGTOOLERR_FILENOTFOUND; - - bytes_left = (uint32_t) sourcef.size(); - - err = fat_set_file_size(partition, &file, bytes_left); - if (err) - return err; - - while(bytes_left > 0) - { - len = (std::min)(bytes_left, sizeof(buffer)); - sourcef.read(buffer, len); - - err = fat_write_file(partition, &file, buffer, len, NULL); - if (err) - return err; - - bytes_left -= len; - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_partition_delete(imgtool::partition &partition, const char *filename, unsigned int dir) -{ - imgtoolerr_t err; - fat_file file; - fat_dirent ent; - - err = fat_lookup_path(partition, filename, CREATE_NONE, &file); - if (err) - return err; - if (file.directory != dir) - return IMGTOOLERR_FILENOTFOUND; - - if (dir) - { - err = fat_read_dirent(partition, &file, ent, NULL); - if (err) - return err; - if (!ent.eof) - return IMGTOOLERR_DIRNOTEMPTY; - } - - err = fat_set_file_size(partition, &file, ~0); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_partition_deletefile(imgtool::partition &partition, const char *filename) -{ - return fat_partition_delete(partition, filename, 0); -} - - - -static imgtoolerr_t fat_partition_freespace(imgtool::partition &partition, uint64_t *size) -{ - imgtoolerr_t err; - const fat_partition_info *disk_info; - uint8_t *fat_table; - uint32_t i; - - disk_info = fat_get_partition_info(partition); - - err = fat_load_fat(partition, &fat_table); - if (err) - goto done; - - *size = 0; - for (i = 2; i < disk_info->total_clusters; i++) - { - if (fat_get_fat_entry(partition, fat_table, i) == 0) - *size += disk_info->cluster_size; - } - -done: - if (fat_table) - free(fat_table); - return err; -} - - - -static imgtoolerr_t fat_partition_createdir(imgtool::partition &partition, const char *path) -{ - imgtoolerr_t err; - fat_file file; - uint8_t initial_data[64]; - - err = fat_lookup_path(partition, path, CREATE_DIR, &file); - if (err) - return err; - if (!file.directory) - return IMGTOOLERR_FILENOTFOUND; - - err = fat_set_file_size(partition, &file, sizeof(initial_data)); - if (err) - return err; - - /* 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); - memcpy(&initial_data[32], ". ", 11); - place_integer_le(initial_data, 43, 1, 0x10); - place_integer_le(initial_data, 58, 2, file.parent_first_cluster); - - err = fat_write_file(partition, &file, initial_data, sizeof(initial_data), NULL); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_partition_deletedir(imgtool::partition &partition, const char *path) -{ - return fat_partition_delete(partition, path, 1); -} - - - -void fat_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_SUPPORTS_BOOTBLOCK: info->i = 1; break; - case IMGTOOLINFO_INT_PATH_SEPARATOR: info->i = '\\'; break; - case IMGTOOLINFO_INT_ALTERNATE_PATH_SEPARATOR: info->i = '/'; break; - case IMGTOOLINFO_INT_PARTITION_EXTRA_BYTES: info->i = sizeof(fat_partition_info); break; - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(fat_file); 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\n"); break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case IMGTOOLINFO_PTR_CREATE_PARTITION: info->create_partition = fat_partition_create; break; - case IMGTOOLINFO_PTR_OPEN_PARTITION: info->open_partition = fat_partition_open; break; - case IMGTOOLINFO_PTR_BEGIN_ENUM: info->begin_enum = fat_partition_beginenum; break; - case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = fat_partition_nextenum; break; - case IMGTOOLINFO_PTR_READ_FILE: info->read_file = fat_partition_readfile; break; - case IMGTOOLINFO_PTR_WRITE_FILE: info->write_file = fat_partition_writefile; break; - case IMGTOOLINFO_PTR_DELETE_FILE: info->delete_file = fat_partition_deletefile; break; - case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = fat_partition_freespace; break; - case IMGTOOLINFO_PTR_CREATE_DIR: info->create_dir = fat_partition_createdir; break; - case IMGTOOLINFO_PTR_DELETE_DIR: info->delete_dir = fat_partition_deletedir; break; - } -} diff --git a/src/tools/imgtool/modules/fat.h b/src/tools/imgtool/modules/fat.h deleted file mode 100644 index 8e7c60d..0000000 --- a/src/tools/imgtool/modules/fat.h +++ /dev/null @@ -1,6 +0,0 @@ -// 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 deleted file mode 100644 index 4a008ad..0000000 --- a/src/tools/imgtool/modules/hp48.cpp +++ /dev/null @@ -1,741 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Antoine Mine -/**************************************************************************** - - hp48.cpp - - Memory cards for HP48 SX/GX - - Antoine Mine' 2014 - -***************************************************************************** -*/ - -/* - HP memory cards can contain two kinds of objects: - - attached libraries - - backup objects (encapsulating any kind of object) - - Attached libraries appear with a LIB attribute in imgtool's listing, and in - the global "LIBRARY" menu on the HP48. - Backup objects appear with a BAK attribute in imgtool's listing, and - in the relevant "PORTS" menu on the HP48. - - Currently, we only support storing host files into backup objects and - retreiving backup objects into files. - For attached library objects in the memory card, we only show their name, but - cannot retrieve their contents. - - To install a library contained in a host file, copy it with imgtool to - the card; it creates a backup object visible in the "PORTS" menu; - then evalue the object, store it into some port (e.g, 0 STO), - turn off the HP48 and back on; the library should now be attached and - visible in the "LIBRARY" menu. - (The process is similar to installing a library from a file you get - from the serial interface.) -*/ - - -/* - HP memory cards have size from 32 KB to 4096 KB. - However, cards with size greater than 128 KB are seen as multiple ports of - size 128 KB on the HP48 GX. In imgtool, we see them as distinct 128 KB - partitions. - Unfortunately, at the moment, partitions do not seem to be supported in the - command-line tool... - */ - - -/* - Here is the format of backup objects (addresses are in 4-bit nibbles): - - offset field size value - 0 prolog 5 02B62 prolog for overall backup object - 5 size 5 len total size in nibble without prolog - 10 name length 2 nbcar object name, in characters - 12 name 2*nbcar - - 12+2*nbcar name length 2 nbcar same value as name length at 10 - 14+2*nbcar object - - - len-5 prolog 5 02911 prolog for inlined system integer - len - 1 0 - len+1 CRC 4 - CRC from 5 to len - - total length: len+4 - - i.e., the backup object is a container containing the object name - and two objects: the backuped object itself and a system integer - that contains the CRC. - - HP48 host files start with a "HPHP48-X" header (where X can be any - single letter, which denotes a ROM revision and, implicitly, whether - the program is for the S/SX or the G/GX family). - When storing a file to the memory card, we strip the header and - embed the object into a backup object with the correct CRC. - When copying from the memory card to a host file, we extract the object - from the backup container, stripping its CRC, and add the HPHP48-X header. - - */ - - - - - -/***************************************************************************** - Includes -*****************************************************************************/ - -#include "imgtool.h" - -#include "opresolv.h" - - - -/***************************************************************************** - Data structures -*****************************************************************************/ - - -struct hp48_card -{ - imgtool::stream *stream; - int modified; - - /* size, in bytes of card data: from 32 KB to 4 MB */ - int size; - - /* we store each nibble (4-bit) into its own byte, for simpler addressing; - hence, data has 2*size - */ - uint8_t* data; - -}; - -struct hp48_partition -{ - /* pointer to the beginning of the partition inside the hp48_card */ - uint8_t* data; - - /* size, in bytes (128 KB or less) */ - int size; - -}; - -struct hp48_directory -{ - int pos; -}; - - -#define PROLOG_BACKUP 0x02B62 -#define PROLOG_LIBRARY 0x02B40 -#define PROLOG_SYSINT 0x02911 - -/* memory cards are composed solely of libraries and backup objects */ -#define IS_OBJECT(prolog) ((prolog) == PROLOG_LIBRARY || (prolog) == PROLOG_BACKUP) - -/* host files begin with this prefix (up to the last letter) */ -static const char* hp48_prefix = "HPHP48-R"; - - - -OPTION_GUIDE_START( hp48_create_optionguide ) - OPTION_INT('S', "size", "Size in KB" ) -OPTION_GUIDE_END - -/* size in KB, 128 KB being the default */ -static const char hp48_create_optionspec[] = "S32/64/[128]/256/512/1024/2048/4096"; - - - -/***************************************************************************** - Utility functions -*****************************************************************************/ - - -static hp48_card *get_hp48_card(imgtool::image &image) -{ - return (hp48_card*) image.extra_bytes(); -} - -/* byes to nibbles */ -static void unpack(uint8_t* dst, uint8_t* src, int nsize) -{ - int i; - - if ( nsize & 1 ) - { - dst[nsize-1] = src[nsize/2] & 0xf; - } - - for ( i = nsize/2-1; i >= 0; i-- ) - { - dst[2*i+1] = src[i] >> 4; - dst[2*i ] = src[i] & 0xf; - } -} - -/* nibbles to bytes */ -static void pack(uint8_t* dst, uint8_t* src, int nsize) -{ - int i; - - for ( i = 0 ; i < nsize/2; i++ ) - { - dst[i] = (src[2*i] & 0xf) | (src[2*i+1] << 4); - } - - if ( nsize & 1 ) - { - dst[nsize/2] = src[nsize-1] & 0xf; - } - } - - -static int read20(uint8_t* data) -{ - return data[0] | (data[1] << 4) | (data[2] << 8) | (data[3] << 12) | (data[4] << 16); -} - -static int read8(uint8_t* data) -{ - return data[0] | (data[1] << 4); -} - -static void readstring(char* dst, uint8_t* data, int nb) -{ - int i; - for ( i = 0; i < nb; i++ ) - { - dst[i] = read8( data + 2*i ); - } - dst[nb] = 0; -} - -static void write20(uint8_t* data, int v) -{ - data[0] = v & 0xf; - data[1] = (v >> 4) & 0xf; - data[2] = (v >> 8) & 0xf; - data[3] = (v >> 12) & 0xf; - data[4] = (v >> 16) & 0xf; -} - -static void write8(uint8_t* data, int v) -{ - data[0] = v & 0xf; - data[1] = (v >> 4) & 0xf; -} - -static void writestring(uint8_t* data, const char* str, int nb) -{ - int i; - for ( i = 0; i < nb; i++ ) - { - write8( data + 2*i, str[i] ); - } -} - - -/* go to the end, return its offset */ -static int find_end(hp48_partition* p) -{ - int pos = 0; - while (1) - { - if ( pos + 10 > 2*p->size) break; - - int prolog = read20( p->data + pos ); - if ( !IS_OBJECT( prolog )) break; - - pos += read20( p->data + pos + 5 ) + 5; - } - - if ( pos > 2*p->size ) pos = 2*p->size; - return pos; -} - - -/* find the backup object with the given name, returns its offset or -1 (not found) */ -static int find_file(hp48_partition* p, const char* filename, int *ptotalsize, int* pstart, int* pcontentsize) -{ - uint8_t* data = p->data; - int pos = 0; - - /* find file */ - while (1) - { - if ( pos + 10 > 2*p->size) return -1; - - /* get prolog */ - int prolog = read20( data+pos ); - if ( !IS_OBJECT(prolog)) return -1; - - /* get size */ - int totalsize = read20( data+pos+5 ); - if ( totalsize < 14) return -1; - if ( pos + 5 + totalsize > 2*p->size ) return -1; - - if ( prolog == PROLOG_BACKUP ) - { - /* get name */ - int namelen = read8( data + pos + 10 ); - char name[257]; - if ( 9 + 2*namelen > totalsize ) return -1; - readstring( name, data + pos + 12, namelen ); - - /* check name */ - if ( !strcmp( name, filename ) ) - { - /* found! */ - if ( ptotalsize ) *ptotalsize = totalsize; - if ( pstart ) *pstart = pos + 14 + 2*namelen; - if ( pcontentsize ) *pcontentsize = totalsize - (9 + 2*namelen); - return pos; - } - else - { - /* skip */ - pos += totalsize + 5; - } - } - else - { - /* skip */ - pos += totalsize + 5; - } - - } - - // never executed - //return -1; -} - - -/* CRC computing. - This is the same CRC that is computed by the HP48 hardware. - */ -static uint16_t crc(uint8_t* data, int len) -{ - uint16_t crc = 0; - int i; - - for ( i = 0; i < len; i++ ) - { - crc = (crc >> 4) ^ (((crc ^ data[i]) & 0xf) * 0x1081); - } - - return crc; -} - - - -/***************************************************************************** - Imgtool functions -*****************************************************************************/ - - -static imgtoolerr_t hp48_open(imgtool::image &img, imgtool::stream::ptr &&stream) -{ - hp48_card* c = get_hp48_card(img); - int size = stream->size(); - - /* check that size is a power of 2 between 32 KB and 4 MG */ - if ( (size < 32 * 1024) || - (size > 4 * 1024 * 1024) || - (size & (size-1)) ) - { - return IMGTOOLERR_CORRUPTIMAGE; - } - - /* store info */ - c->stream = stream.get(); - c->modified = 0; - c->size = size; - c->data = (uint8_t*) malloc( 2 * size ); - if ( !c->data ) - { - return IMGTOOLERR_READERROR; - } - - /* fully load image */ - c->stream->seek(0, SEEK_SET); - if (c->stream->read(c->data, size) < size) - { - return IMGTOOLERR_READERROR; - } - unpack( c->data, c->data, 2 * size ); - - c->stream = stream.release(); - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t hp48_create(imgtool::image &img, - imgtool::stream::ptr &&stream, - util::option_resolution *opts) -{ - hp48_card* c = get_hp48_card(img); - int size; - - size = opts->lookup_int('S'); - - c->stream = stream.get(); - c->modified = 1; - c->size = size * 1024; - c->data = (uint8_t*) malloc( 2 * c->size ); - if ( !c->data ) - { - return IMGTOOLERR_READERROR; - } - - /* zeroing the image seems fine */ - memset( c->data, 0, 2 * c->size ); - - c->stream = stream.release(); - return IMGTOOLERR_SUCCESS; -} - - - -static void hp48_close(imgtool::image &img) -{ - hp48_card* c = get_hp48_card(img); - - if ( c->modified ) - { - /* save image */ - pack( c->data, c->data, 2 * c->size ); - c->stream->seek(0, SEEK_SET); - c->stream->write(c->data, c->size); - } - - /* clean up */ - free( c->data ); - delete c->stream; -} - - - -/* each 128 KB chunk is a distinct partition */ -#define MAX_PORT_SIZE (128*1024) - -void hp48_partition_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info); - -static imgtoolerr_t hp48_list_partitions(imgtool::image &img, std::vector &partitions) -{ - hp48_card* c = get_hp48_card(img); - - int i; - for (i = 0; i * MAX_PORT_SIZE < c->size ; i++) - { - // offset and size in bytes - uint64_t base_block = i * MAX_PORT_SIZE; - uint64_t block_count = std::min((uint64_t)c->size - base_block, (uint64_t)MAX_PORT_SIZE); - - // append the partition - partitions.emplace_back(hp48_partition_get_info, base_block, block_count); - } - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t hp48_open_partition(imgtool::partition &part, - uint64_t first_block, uint64_t block_count) -{ - imgtool::image &img(part.image()); - hp48_card* c = get_hp48_card(img); - hp48_partition* p = (hp48_partition*) part.extra_bytes(); - - if ( first_block + block_count > c->size ) - return IMGTOOLERR_INVALIDPARTITION; - - /* store partition position */ - p->data = c->data + first_block; - p->size = block_count; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t hp48_beginenum(imgtool::directory &enumeration, const char *path) -{ - hp48_directory* d = (hp48_directory*) enumeration.extra_bytes(); - - d->pos = 0; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t hp48_nextenum(imgtool::directory &enumeration, imgtool_dirent &ent) -{ - imgtool::partition &part(enumeration.partition()); - //imgtool::image &img(part.image()); - //hp48_card* c = get_hp48_card(img); - hp48_partition* p = (hp48_partition*) part.extra_bytes(); - hp48_directory* d = (hp48_directory*) enumeration.extra_bytes(); - - uint8_t* data = p->data; - int pos = d->pos; - - if ( pos < 0 || pos+12 > 2*p->size ) - { - ent.eof = 1; - return IMGTOOLERR_SUCCESS; - } - - int prolog = read20( data+pos ); - - if ( IS_OBJECT(prolog) ) - { - pos += 5; - int totalsize = read20( data+pos ); - pos += 5; - - int namelen = read8( data+pos ); - pos += 2; - if ( (pos + 2*namelen > 2*p->size) || - (namelen >= sizeof(ent.filename)) ) - { - ent.eof = 1; - return IMGTOOLERR_CORRUPTFILE; - } - readstring( ent.filename, data+pos, namelen ); - - /* compute size in bytes, removing name, length & CRC fields */ - ent.filesize = ((totalsize - 19 - 2*namelen) + 1) / 2; - - switch (prolog) - { - case PROLOG_LIBRARY: strncpy( ent.attr, "LIB", sizeof(ent.attr) ); break; - case PROLOG_BACKUP: strncpy( ent.attr, "BAK", sizeof(ent.attr) ); break; - default: strncpy( ent.attr, "?", sizeof(ent.attr) ); - } - - d->pos = d->pos + totalsize + 5; - } - else - { - /* 0 or unknown object => end */ - ent.eof = 1; - } - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t hp48_freespace(imgtool::partition &part, uint64_t *size) -{ - //imgtool::image &img(part.image()); - //hp48_card* c = get_hp48_card(img); - hp48_partition* p = (hp48_partition*) part.extra_bytes(); - - *size = p->size - (find_end(p)+1)/2; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t hp48_readfile(imgtool::partition &part, - const char *filename, - const char *fork, - imgtool::stream &destf) -{ - //imgtool::image &img(part.image()); - //hp48_card* c = get_hp48_card(img); - hp48_partition* p = (hp48_partition*) part.extra_bytes(); - - /* find entry */ - int totalsize, start, size; - int pos = find_file(p, filename, &totalsize, &start, &size); - if ( pos == -1 ) - { - return IMGTOOLERR_FILENOTFOUND; - } - - /* CRC check */ - uint16_t objcrc = read20( p->data + pos + totalsize ) >> 4; - uint16_t mycrc = crc( p->data + pos + 5, totalsize - 4); - if ( objcrc != mycrc ) - { - return IMGTOOLERR_CORRUPTIMAGE; - } - size -= 10; - - /* save header */ - destf.write(hp48_prefix, 8); - - /* save contents to host file */ - int bytesize = (size + 1) / 2; - uint8_t* buf = (uint8_t*) malloc( bytesize ); - if (!buf) - { - return IMGTOOLERR_FILENOTFOUND; - } - pack( buf, p->data + start, size ); - destf.write(buf, bytesize); - free( buf ); - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t hp48_deletefile(imgtool::partition &part, - const char *filename) -{ - imgtool::image &img(part.image()); - hp48_card* c = get_hp48_card(img); - hp48_partition* p = (hp48_partition*) part.extra_bytes(); - - /* find entry */ - int totalsize; - int pos = find_file(p, filename, &totalsize, NULL, NULL ); - if ( pos == -1 ) - { - return IMGTOOLERR_FILENOTFOUND; - } - - /* move */ - totalsize += 5; - memmove( p->data+pos, p->data+pos+totalsize, 2*p->size-(pos+totalsize) ); - memset( p->data + 2*p->size-totalsize, 0, totalsize); - c->modified = 1; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t hp48_writefile(imgtool::partition &part, - const char *filename, - const char *fork, - imgtool::stream &sourcef, - util::option_resolution *opts) -{ - imgtool::image &img(part.image()); - hp48_card* c = get_hp48_card(img); - hp48_partition* p = (hp48_partition*) part.extra_bytes(); - - /* check header */ - char head[8]; - sourcef.read(head, 8); - if ( memcmp( head, hp48_prefix, 7) ) - { - return IMGTOOLERR_READERROR; - } - - /* ensure that the file does not exist */ - /* TODO: resize the existing file instead, to keep it in place? */ - hp48_deletefile( part, filename ); - - /* goto end */ - //uint8_t* data = p->data; - int pos = find_end(p); - - int len = strlen( filename ); - if ( len > 255 ) len = 255; - - /* check size */ - int filesize = sourcef.size() - 8; - if ( pos + 2*filesize + 24 + 2*len > 2 * p->size ) - { - return IMGTOOLERR_NOSPACE; - } - - /* load file */ - uint8_t* buf = (uint8_t*) malloc( filesize ); - if ( !buf ) return IMGTOOLERR_NOSPACE; - sourcef.read(buf, filesize); - - /* store backup object */ - int org = pos; - int totalsize = 2*filesize + 19 + 2*len; - write20( p->data+pos, PROLOG_BACKUP ); - pos +=5; - write20( p->data+pos, totalsize ); - pos +=5; - write8( p->data+pos, len ); - pos += 2; - writestring( p->data+pos, filename, len ); - pos += 2*len; - write8( p->data+pos, len ); - pos += 2; - unpack( p->data+pos, buf, 2*filesize ); - pos += 2*filesize; - - /* store crc */ - write20( p->data+pos, PROLOG_SYSINT ); - pos += 5; - p->data[pos] = 0; - write20( p->data+pos, crc(p->data+org+5, totalsize-4) << 4 ); - - free(buf); - - c->modified = 1; - - return IMGTOOLERR_SUCCESS; -} - - - - -/***************************************************************************** - Imgtool module declaration -*****************************************************************************/ - - - -void hp48_partition_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(), "hp48"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "HP48 SX/GX memory card"); break; - case IMGTOOLINFO_STR_FILE: strcpy(info->s = imgtool_temp_str(), __FILE__); break; - case IMGTOOLINFO_STR_FILE_EXTENSIONS: strcpy(info->s = imgtool_temp_str(), "crd"); break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case IMGTOOLINFO_PTR_OPEN_PARTITION: info->open_partition = hp48_open_partition; break; - case IMGTOOLINFO_PTR_CLOSE: info->close = hp48_close; break; - case IMGTOOLINFO_PTR_BEGIN_ENUM: info->begin_enum = hp48_beginenum; break; - case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = hp48_nextenum; break; - case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = hp48_freespace; break; - case IMGTOOLINFO_PTR_READ_FILE: info->read_file = hp48_readfile; break; - case IMGTOOLINFO_PTR_WRITE_FILE: info->write_file = hp48_writefile; break; - case IMGTOOLINFO_PTR_DELETE_FILE: info->delete_file = hp48_deletefile; break; - - case IMGTOOLINFO_INT_PARTITION_EXTRA_BYTES: info->i = sizeof(hp48_partition); break; - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(hp48_directory); break; - - } -} - -void hp48_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(), "hp48"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "HP48 SX/GX memory card"); break; - case IMGTOOLINFO_STR_FILE: strcpy(info->s = imgtool_temp_str(), __FILE__); break; - case IMGTOOLINFO_STR_FILE_EXTENSIONS: strcpy(info->s = imgtool_temp_str(), "crd"); break; - case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC: strcpy(info->s = imgtool_temp_str(), hp48_create_optionspec); break; - - case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE: info->createimage_optguide = &hp48_create_optionguide; break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case IMGTOOLINFO_PTR_OPEN: info->open = hp48_open; break; - case IMGTOOLINFO_PTR_CREATE: info->create = hp48_create; break; - case IMGTOOLINFO_PTR_CLOSE: info->close = hp48_close; break; - case IMGTOOLINFO_PTR_LIST_PARTITIONS: info->list_partitions = hp48_list_partitions; break; - - case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES: info->i = sizeof(hp48_card); break; - } -} diff --git a/src/tools/imgtool/modules/hp85_tape.cpp b/src/tools/imgtool/modules/hp85_tape.cpp deleted file mode 100644 index 14103fc..0000000 --- a/src/tools/imgtool/modules/hp85_tape.cpp +++ /dev/null @@ -1,1164 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:F. Ulivi -/********************************************************************* - - hp85_tape.cpp - - HP-85 tape format - -*********************************************************************/ -#include "imgtool.h" - -#include "formats/hti_tape.h" -#include "formats/imageutl.h" - -#include "ioprocs.h" -#include "opresolv.h" - -#include -#include - - -// Constants -static constexpr unsigned CHARS_PER_FNAME = 6; // Characters in a filename -static constexpr unsigned CHARS_PER_EXT = 4; // Characters in (simulated) file extension -static constexpr unsigned CHARS_PER_FNAME_EXT = CHARS_PER_FNAME + 1 + CHARS_PER_EXT; // Characters in filename + extension -static constexpr unsigned MAX_FILE_NO = 42; // Maximum file # -static constexpr unsigned MAX_RECORD_SIZE = 256; // Maximum size of record body -static constexpr unsigned MAX_N_RECORDS = 436 * 2 - 5; // Total user-available capacity of tape (in physical records) -static constexpr unsigned DIR_RECORDS = 4; // Records reserved to directory - -// Words stored on tape -using tape_word_t = hti_format_t::tape_word_t; - -// Tape position, 1 unit = 1 inch / (968 * 1024) -using tape_pos_t = hti_format_t::tape_pos_t; - -// File number [0..42] -typedef uint8_t file_no_t; - -// Minimum gap size to detect IFGs: 1.25" -static constexpr tape_pos_t MIN_IFG_SIZE = 1.25 * hti_format_t::ONE_INCH_POS; - -// Minimum gap size to detect IRGs: 1/32 " -static constexpr tape_pos_t MIN_IRG_SIZE = hti_format_t::ONE_INCH_POS / 32; - -// Formatted size of IFGs: 2.5" -static constexpr tape_pos_t FMT_IFG_SIZE = 2.5 * hti_format_t::ONE_INCH_POS; - -// Formatted size of IRGs: 1" -static constexpr tape_pos_t FMT_IRG_SIZE = hti_format_t::ONE_INCH_POS; - -// Formatted size of records: 2.67" -static constexpr tape_pos_t FMT_REC_SIZE = 2.67 * hti_format_t::ONE_INCH_POS; - -// Starting position on tracks: 74" from beginning of tape -static constexpr tape_pos_t TRACK_START = 74 * hti_format_t::ONE_INCH_POS; - -// Sync word: 0x0001 -static constexpr tape_word_t SYNC_WORD = 1; - -// Name of erased (NULL) files -static const char *const NULL_FILENAME = "==NULL=="; - -// Masks of bits in file type -static constexpr uint8_t FT_NEXT_AV_MASK = 0x80; // Next available slot -static constexpr uint8_t FT_NULL_FILE_MASK = 0x40; // Erased file -static constexpr uint8_t FT_PROG_MASK = 0x20; // PROG (BASIC) file -static constexpr uint8_t FT_DATA_MASK = 0x10; // DATA file -static constexpr uint8_t FT_BPGM_MASK = 0x08; // BPGM file -static constexpr uint8_t FT_WP_MASK = 0x02; // Write protection -static constexpr uint8_t FT_HIDDEN_MASK = 0x01; // Hidden file - -/******************************************************************************** - * Directory entries - ********************************************************************************/ -struct dir_entry_85 { - uint8_t filename[ CHARS_PER_FNAME ]; // Filename (left justified, space-padded on the right) - file_no_t file_no; // File # - uint8_t filetype; // File type - uint16_t n_recs; // Physical records - uint16_t record_len; // Length of logical records -}; - -/******************************************************************************** - * Tape image - ********************************************************************************/ -class tape_image_85 { -public: - tape_image_85(void); - - bool is_dirty(void) const { return dirty; } - - void format_img(void); - - imgtoolerr_t load_from_file(imgtool::stream *stream); - typedef std::vector sif_file_t; - typedef std::unique_ptr sif_file_ptr_t; - bool load_sif_file(file_no_t file_no , sif_file_t& out); - imgtoolerr_t save_to_file(imgtool::stream *stream); - - bool get_dir_entry(unsigned idx , const dir_entry_85*& entry) const; - bool find_file(const char *filename , bool ignore_ext , unsigned& idx) const; - bool alloc_new_file(dir_entry_85*& entry , sif_file_ptr_t&& file_data); - bool delete_dir_entry(unsigned idx); - bool finalize_allocation(); - static void get_filename_and_ext(const dir_entry_85& ent , bool inc_ext , char *out); - static void split_filename_and_ext(const char *filename , char *fname , char *ext); - -private: - // Tape image - hti_format_t image; - bool dirty; - // Directory - std::vector dir; - // Content - std::vector content; - // First file on track 1 - file_no_t file_track_1; - // No. of first record on track 1 - uint16_t record_track_1; - - 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(); - static tape_word_t checksum(const tape_word_t *block , unsigned block_len); - bool decode_dir(const sif_file_t& file_0); - void encode_dir(sif_file_t& file_0) const; - void save_words(unsigned track , tape_pos_t& pos , const tape_word_t *block , unsigned block_len); - void save_sif_file(unsigned& track , tape_pos_t& pos , file_no_t file_no , const sif_file_t& in); - static bool filename_char_check(uint8_t c); - static bool filename_check(const uint8_t *filename); -}; - -/******************************************************************************** - * Image state - ********************************************************************************/ -typedef struct { - imgtool::stream *stream; - tape_image_85 *img; -} tape_state_t; - -/******************************************************************************** - * Directory enumeration - ********************************************************************************/ -typedef struct { - unsigned dir_idx; -} dir_state_t; - -/******************************************************************************** - * Internal functions - ********************************************************************************/ -tape_image_85::tape_image_85(void) - : dirty(false) -{ - image.set_image_format(hti_format_t::HTI_DELTA_MOD_16_BITS); -} - -void tape_image_85::format_img(void) -{ - // Create an empty directory - dir.clear(); - content.clear(); - - // Allocate space - finalize_allocation(); -} - -imgtoolerr_t tape_image_85::load_from_file(imgtool::stream *stream) -{ - 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; - - // Get directory (file #0) - sif_file_t file_0; - if (!load_sif_file(0 , file_0)) { - return IMGTOOLERR_CORRUPTDIR; - } - - if (!decode_dir(file_0)) { - return IMGTOOLERR_CORRUPTDIR; - } - - dirty = false; - - return IMGTOOLERR_SUCCESS; -} - -bool tape_image_85::load_sif_file(file_no_t file_no , sif_file_t& out) -{ - unsigned track; - unsigned gaps_to_go; - - // What track is the file on? - if (!file_track_1 || file_no < file_track_1 || (file_no == file_track_1 && record_track_1)) { - track = 0; - gaps_to_go = file_no + 1; - } else { - track = 1; - gaps_to_go = file_no - file_track_1; - if (!record_track_1) { - gaps_to_go++; - } - } - tape_pos_t pos = 0; - - hti_format_t::track_iterator_t it; - while (gaps_to_go--) { - // Search for IFG - if (!image.next_data(track , pos , true , false , it)) { - return false; - } - pos = it->first; - if (!image.next_gap(track , pos , true , MIN_IFG_SIZE)) { - return false; - } - } - - // Get back to the start of record before the gap - image.next_data(track , pos , false , false , it); - pos = it->first; - bool direction = false; - - uint16_t expected_rec_no = 0; - - out.clear(); - - while (true) { - image.next_gap(track , pos , direction , MIN_IRG_SIZE); - // Read record header - if (!image.next_data(track , pos , true , false , it)) { - break; - } - unsigned bit_idx = 15; - if (!image.sync_with_record(track , it , bit_idx)) { - // Couldn't align - return false; - } - - // 0 File word - // 1 Record word - // 2 Length word - // 3 Checksum - tape_word_t hdr[ 4 ]; - for (unsigned i = 0; i < 4; i++) { - auto res = image.next_word(track , it , bit_idx , hdr[ i ]); - if (res != hti_format_t::ADV_CONT_DATA) { - return false; - } - } - if (checksum(&hdr[ 0 ] , 3) != hdr[ 3 ]) { - return false; - } - - file_no_t hdr_file_no; - uint16_t hdr_rec_no; - bool hdr_has_body; - unsigned hdr_body_len; - - if (!dec_rec_header(&hdr[ 0 ] , hdr_file_no , hdr_rec_no , hdr_has_body , hdr_body_len)) { - return false; - } - - if (hdr_file_no != file_no) { - break; - } - if (!hdr_has_body || !hdr_body_len) { - return true; - } - if (hdr_rec_no != expected_rec_no) { - return false; - } - - tape_word_t body[ MAX_RECORD_SIZE / 2 + 1 ]; - unsigned word_no = (hdr_body_len + 1) / 2 + 1; - for (unsigned i = 0; i < word_no; i++) { - auto res = image.next_word(track , it , bit_idx , body[ i ]); - if (res != hti_format_t::ADV_CONT_DATA) { - return false; - } - } - if (checksum(&body[ 0 ] , word_no - 1) != body[ word_no - 1 ]) { - return false; - } - for (unsigned i = 0; i < hdr_body_len; i++) { - tape_word_t tmp = body[ i / 2 ]; - out.push_back((uint8_t)(tmp >> 8)); - i++; - if (i < hdr_body_len) { - out.push_back((uint8_t)(tmp & 0xff)); - } - } - - // Move to next record (possibly crossing into track 1) - expected_rec_no++; - if (file_no == file_track_1 && expected_rec_no == record_track_1) { - track = 1; - pos = 0; - } else { - pos = it->first; - } - direction = true; - - if (hdr_body_len < MAX_RECORD_SIZE) { - break; - } - } - - return expected_rec_no != 0; -} - -bool tape_image_85::load_whole_tape() -{ - content.clear(); - - for (const auto& i : dir) { - sif_file_ptr_t file; - if (!(i.filetype & FT_NULL_FILE_MASK)) { - file = std::make_unique(); - if (!load_sif_file(i.file_no, *file)) { - return false; - } - } - content.push_back(std::move(file)); - } - - return true; -} - -bool tape_image_85::dec_rec_header(const tape_word_t *hdr , file_no_t& file_no , uint16_t& rec_no , bool& has_body , unsigned& body_len) -{ - if ((hdr[ 0 ] & 0x6000) != 0x2000 || - (hdr[ 0 ] & 0x07ff) > MAX_FILE_NO || - (hdr[ 1 ] & 0xf000) != 0x1000) { - return false; - } - file_no = (file_no_t)(hdr[ 0 ] & 0xff); - rec_no = (uint16_t)(hdr[ 1 ] & 0xfff); - has_body = (hdr[ 0 ] & 0x1800) != 0; - - bool has_file_id = (hdr[ 0 ] & 0x8000) != 0; - if (has_file_id != (rec_no == 0)) { - return false; - } - - if (has_body) { - if ((hdr[ 2 ] & 0xff00) != 0xff00) { - return false; - } - body_len = hdr[ 2 ] & 0xff; - if (body_len) { - body_len++; - } - } else { - body_len = 0; - } - - return true; -} - -tape_word_t tape_image_85::checksum(const tape_word_t *block , unsigned block_len) -{ - tape_word_t csum = 0; - for (unsigned i = 0; i < block_len; i++) { - csum += *block++; - } - return csum & 0xffff; -} - -imgtoolerr_t tape_image_85::save_to_file(imgtool::stream *stream) -{ - sif_file_t file_0; - - encode_dir(file_0); - - unsigned track = 0; - tape_pos_t pos = TRACK_START; - - image.clear_tape(); - - save_sif_file(track , pos , 0 , file_0); - - for (auto i = dir.cbegin(); i != dir.cend(); i++) { - file_no_t file_no = i - dir.cbegin(); - save_sif_file(track , pos , file_no + 1 , *content[ file_no ]); - } - - // Empty file at the end - file_0.clear(); - save_sif_file(track , pos , dir.size() + 1 , file_0); - - image.save_tape(*imgtool::stream_read_write(*stream, 0)); - - return IMGTOOLERR_SUCCESS; -} - -bool tape_image_85::get_dir_entry(unsigned idx , const dir_entry_85*& entry) const -{ - if (idx >= dir.size()) { - return false; - } else { - entry = &dir[ idx ]; - return true; - } -} - -bool tape_image_85::find_file(const char *filename , bool ignore_ext , unsigned& idx) const -{ - if (strcmp(filename , NULL_FILENAME) == 0) { - return false; - } - - char fname[ CHARS_PER_FNAME_EXT + 1 ]; - char ext[ CHARS_PER_EXT + 1 ]; - - split_filename_and_ext(filename, fname, ext); - - bool has_ext = !ignore_ext && *ext != '\0'; - - if (has_ext) { - strcat(fname , "."); - strcat(fname , ext); - } - - for (auto i = dir.cbegin(); i < dir.cend(); i++) { - if (i->filetype & FT_NULL_FILE_MASK) { - continue; - } - char full_fname[ CHARS_PER_FNAME_EXT + 1 ]; - - get_filename_and_ext(*i, has_ext, full_fname); - - if (strcmp(fname , full_fname) == 0) { - idx = i - dir.cbegin(); - return true; - } - } - - return false; -} - -bool tape_image_85::alloc_new_file(dir_entry_85*& entry , sif_file_ptr_t&& file_data) -{ - if (file_data->size() > MAX_N_RECORDS * MAX_RECORD_SIZE) { - // File bigger than tape capacity - return false; - } - - if (!load_whole_tape()) { - return false; - } - - dir_entry_85 new_entry; - memset(&new_entry , 0 , sizeof(new_entry)); - - unsigned idx = MAX_FILE_NO; - for (auto i = dir.cbegin(); i != dir.cend(); i++) { - if (i->filetype & FT_NULL_FILE_MASK) { - idx = i - dir.cbegin(); - break; - } - } - if (idx >= MAX_FILE_NO) { - idx = dir.size(); - if (idx >= MAX_FILE_NO) { - return false; - } - dir.push_back(new_entry); - content.push_back(std::make_unique()); - } else { - dir[ idx ] = new_entry; - } - entry = &dir[ idx ]; - - content[ idx ] = std::move(file_data); - - return true; -} - -bool tape_image_85::delete_dir_entry(unsigned idx) -{ - if (idx < dir.size()) { - dir[ idx ].filetype = FT_NULL_FILE_MASK; - return load_whole_tape(); - } else { - return false; - } -} - -bool tape_image_85::finalize_allocation() -{ - tape_pos_t hole_pos = hti_format_t::next_hole(TRACK_START , true); - - for (unsigned i = 0; i < dir.size(); i++) { - if (dir[ i ].filetype & FT_NULL_FILE_MASK) { - dir.erase(dir.begin() + i); - content.erase(content.begin() + i); - i--; - } - } - - unsigned track = 0; - // Position where file #1 starts (that is, after directory) - tape_pos_t pos = TRACK_START + FMT_REC_SIZE * DIR_RECORDS + FMT_IRG_SIZE * (DIR_RECORDS - 1) + FMT_IFG_SIZE; - - file_track_1 = 0; - record_track_1 = 0; - - for (auto i = dir.begin(); i != dir.end(); i++) { - file_no_t file_no = i - dir.begin(); - unsigned recs = (content[ file_no ]->size() + MAX_RECORD_SIZE - 1) / MAX_RECORD_SIZE; - if (!recs) { - // Always at least 1 record - recs = 1; - } - i->file_no = file_no + 1; - i->n_recs = recs; - // Size of file on tape: "recs" records, 1 IFG between record 0 and 1, IRGs between all - // other records - tape_pos_t file_size = FMT_IFG_SIZE + recs * FMT_REC_SIZE + (recs - 1) * FMT_IRG_SIZE; - tape_pos_t rec1_start = pos + FMT_REC_SIZE + FMT_IFG_SIZE; - tape_pos_t next_track_pos = 0; - if (pos <= hole_pos && hole_pos < rec1_start) { - // Hole on record #0 - file_track_1 = file_no + 1; - record_track_1 = 1; - next_track_pos = rec1_start; - } else if (rec1_start <= hole_pos && hole_pos < (pos + file_size)) { - // Hole in this file, records from 1 on - file_track_1 = file_no + 1; - record_track_1 = (hole_pos - rec1_start) / (FMT_REC_SIZE + FMT_IRG_SIZE) + 2; - next_track_pos = rec1_start + (record_track_1 - 1) * (FMT_REC_SIZE + FMT_IRG_SIZE); - } - if (next_track_pos) { - // Move to next track - if (++track >= 2) { - // Out of space - return false; - } - pos = pos + file_size - next_track_pos + TRACK_START; - } else { - pos += file_size; - } - } - dirty = true; - return true; -} - -typedef struct { - uint8_t filetype_mask; - const char *ext; -} file_attr_t; - -static const file_attr_t filetype_table[] = { - { FT_PROG_MASK , "PROG" }, - { FT_DATA_MASK , "DATA" }, - { FT_BPGM_MASK , "BPGM" } -}; - -void tape_image_85::get_filename_and_ext(const dir_entry_85& ent , bool inc_ext , char *out) -{ - if (ent.filetype & FT_NULL_FILE_MASK) { - // Empty directory slot - strcpy(out , NULL_FILENAME); - } else { - const uint8_t *s = &ent.filename[ 0 ]; - while (*s != '\0' && *s != ' ' && (s - &ent.filename[ 0 ]) < CHARS_PER_FNAME) { - *out++ = *s++; - } - *out = '\0'; - - // Decode filetype - if (inc_ext) { - const char *ext = nullptr; - for (const auto& i : filetype_table) { - if (ent.filetype & i.filetype_mask) { - ext = i.ext; - break; - } - } - if (ext != nullptr) { - strcat(out , "."); - strcat(out , ext); - } - } - } -} - -void tape_image_85::split_filename_and_ext(const char *filename , char *fname , char *ext) -{ - char *fname_fence = fname + CHARS_PER_FNAME; - - while (fname < fname_fence && *filename != '\0' && *filename != '.') { - *fname++ = *filename++; - } - - *fname = '\0'; - - while (*filename != '\0' && *filename != '.') { - filename++; - } - - if (*filename == '\0') { - *ext = '\0'; - } else { - filename++; - strncpy(ext , filename , CHARS_PER_EXT); - ext[ CHARS_PER_EXT ] = '\0'; - } -} - -bool tape_image_85::decode_dir(const sif_file_t& file_0) -{ - if (file_0.size() != DIR_RECORDS * MAX_RECORD_SIZE) { - return false; - } - dir.clear(); - - // Check DIRSEG (directory segment), i.e. record #0 or #1 of directory - // Check FL1TK1 (file & record no. where track 1 begins) - if (file_0[ 0xfc ] != 0 || - file_0[ 0x1fc ] != 1 || - file_0[ 0xfd ] != file_0[ 0x1fd ] || - file_0[ 0xfe ] != file_0[ 0x1fe ] || - file_0[ 0xff ] != file_0[ 0x1ff ] || - file_0[ 0xfd ] > MAX_FILE_NO) { - return false; - } - - // Get FL1TK1 - file_track_1 = file_0[ 0xfd ]; - record_track_1 = pick_integer_le(file_0.data() , 0xfe , 2); - - file_no_t file_no = 1; - - // Iterate over all entries of directory - for (unsigned i = 0; i < 0x1fc; i += 12) { - if (i == 0xfc) { - // Skip over 1st copy of DIRSEG/FL1TK1 - i = 0x100; - } - const uint8_t *p = file_0.data() + i; - dir_entry_85 new_entry; - - // File type - new_entry.filetype = p[ 7 ]; - if (new_entry.filetype & FT_NEXT_AV_MASK) { - // Directory ends - break; - } - - // Filename - memcpy(&new_entry.filename[ 0 ] , p , CHARS_PER_FNAME); - if (!filename_check(&new_entry.filename[ 0 ])) { - return false; - } - - // File # - // It is also stored at p[ 6 ] but HP85 firmware ignores it - new_entry.file_no = file_no++; - - // Physical records - new_entry.n_recs = pick_integer_le(p , 8 , 2); - - // Bytes per logical record - new_entry.record_len = pick_integer_le(p , 10 , 2); - if (new_entry.record_len < 4 || new_entry.record_len >= 32768) { - return false; - } - - dir.push_back(new_entry); - } - - return true; -} - -void tape_image_85::encode_dir(sif_file_t& file_0) const -{ - file_0.clear(); - file_0.resize(DIR_RECORDS * MAX_RECORD_SIZE , 0); - - // Set DIRSEG - file_0[ 0xfc ] = 0; - 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); - - unsigned i = 0; - file_no_t file_no = 1; - for (auto entry = dir.cbegin(); entry != dir.cend(); entry++, i += 12, file_no++) { - if (i == 0xfc) { - // Skip over 1st copy of DIRSEG/FL1TK1 - i = 0x100; - } - uint8_t *p_entry = file_0.data() + i; - 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); - } - - if (file_no <= MAX_FILE_NO) { - if (i == 0xfc) { - // Skip over 1st copy of DIRSEG/FL1TK1 - i = 0x100; - } - file_0[ i + 7 ] = FT_NEXT_AV_MASK; - } - - // Two identical copies of directory - memcpy(file_0.data() + (DIR_RECORDS / 2) * MAX_RECORD_SIZE , file_0.data() , (DIR_RECORDS / 2) * MAX_RECORD_SIZE); -} - -void tape_image_85::save_words(unsigned track , tape_pos_t& pos , const tape_word_t *block , unsigned block_len) -{ - tape_pos_t length; - for (unsigned i = 0; i < block_len; i++) { - image.write_word(track , pos , *block++ , length); - pos += length; - } -} - -void tape_image_85::save_sif_file(unsigned& track , tape_pos_t& pos , file_no_t file_no , const sif_file_t& in) -{ - unsigned rec_no = 0; - unsigned bytes_to_go = in.size(); - sif_file_t::const_iterator in_it = in.cbegin(); - - do { - if (file_track_1 != 0 && track == 0 && - ((file_no == file_track_1 && rec_no >= record_track_1) || file_no > file_track_1)) { - // Switch to track 1 - track = 1; - pos = TRACK_START; - } - tape_pos_t start_pos = pos; - - unsigned rec_size = std::min(bytes_to_go , MAX_RECORD_SIZE); - - tape_word_t hdr[ 5 ]; - hdr[ 0 ] = SYNC_WORD; - hdr[ 1 ] = (tape_word_t)file_no | 0x2000; - if (rec_no == 0) { - hdr[ 1 ] |= 0x8000; - } - if (rec_size) { - hdr[ 1 ] |= 0x1800; - } - hdr[ 2 ] = 0x1000 | (tape_word_t)rec_no; - hdr[ 3 ] = 0xff00; - if (rec_size) { - hdr[ 3 ] |= (rec_size - 1); - } - hdr[ 4 ] = checksum(&hdr[ 1 ], 3); - - save_words(track, pos, &hdr[ 0 ], 5); - - if (rec_size) { - tape_word_t body[ MAX_RECORD_SIZE / 2 + 1 ]; - unsigned words = 0; - while (words < MAX_RECORD_SIZE / 2 && in_it != in.cend()) { - tape_word_t w = (tape_word_t)*in_it++ << 8; - if (in_it != in.cend()) { - w |= *in_it++; - } - body[ words++ ] = w; - } - body[ words ] = checksum(&body[ 0 ], words); - save_words(track, pos, &body[ 0 ], words + 1); - } - - // Pad record up to FMT_REC_SIZE - tape_word_t filler = 0xffff; - while ((pos - start_pos) < FMT_REC_SIZE) { - save_words(track, pos, &filler, 1); - } - - if (rec_no == 0) { - // IFG - pos = start_pos + FMT_REC_SIZE + FMT_IFG_SIZE; - } else { - // IRG - pos = start_pos + FMT_REC_SIZE + FMT_IRG_SIZE; - } - bytes_to_go -= rec_size; - rec_no++; - } while (bytes_to_go > 0); -} - -bool tape_image_85::filename_char_check(uint8_t c) -{ - // Quotation marks are forbidden in file names - return 0x20 < c && c < 0x7f && c != '"'; -} - -bool tape_image_85::filename_check(const uint8_t *filename) -{ - bool ended = false; - - for (unsigned i = 0; i < CHARS_PER_FNAME; i++) { - uint8_t c = *filename++; - - if (ended) { - if (c != ' ') { - return false; - } - } else if (c == ' ') { - ended = true; - } else if (!filename_char_check(c)) { - return false; - } - } - - return true; -} - -namespace { - tape_state_t& get_tape_state(imgtool::image &img) - { - tape_state_t *ts = (tape_state_t*)img.extra_bytes(); - - return *ts; - } - - tape_image_85& get_tape_image(tape_state_t& ts) - { - if (ts.img == nullptr) { - ts.img = new tape_image_85; - } - - return *(ts.img); - } -} -/******************************************************************************** - * Imgtool functions - ********************************************************************************/ -namespace { - imgtoolerr_t hp85_tape_open(imgtool::image &image, imgtool::stream::ptr &&stream) - { - tape_state_t& state = get_tape_state(image); - - state.stream = stream.release(); - - tape_image_85& tape_image = get_tape_image(state); - - imgtoolerr_t err = tape_image.load_from_file(state.stream); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; - } - - imgtoolerr_t hp85_tape_create(imgtool::image &image, imgtool::stream::ptr &&stream, util::option_resolution *opts) - { - tape_state_t& state = get_tape_state(image); - - state.stream = stream.release(); - - tape_image_85& tape_image = get_tape_image(state); - - tape_image.format_img(); - - return IMGTOOLERR_SUCCESS; - } - - void hp85_tape_close(imgtool::image &image) - { - tape_state_t& state = get_tape_state(image); - tape_image_85& tape_image = get_tape_image(state); - - if (tape_image.is_dirty()) { - (void)tape_image.save_to_file(state.stream); - } - - delete state.stream; - - // Free tape_image - delete &tape_image; - } - - imgtoolerr_t hp85_tape_begin_enum (imgtool::directory &enumeration, const char *path) - { - dir_state_t *ds = (dir_state_t*)enumeration.extra_bytes(); - - ds->dir_idx = 0; - - return IMGTOOLERR_SUCCESS; - } - - imgtoolerr_t hp85_tape_next_enum (imgtool::directory &enumeration, imgtool_dirent &ent) - { - tape_state_t& state = get_tape_state(enumeration.image()); - tape_image_85& tape_image = get_tape_image(state); - dir_state_t *ds = (dir_state_t*)enumeration.extra_bytes(); - - const dir_entry_85 *entry = nullptr; - - if (!tape_image.get_dir_entry(ds->dir_idx, entry)) { - ent.eof = 1; - } else { - ds->dir_idx++; - - unsigned filesize = entry->n_recs * MAX_RECORD_SIZE; - - if (entry->filetype & FT_NULL_FILE_MASK) { - ent.filesize = 0; - } else { - ent.filesize = filesize; - } - - tape_image_85::get_filename_and_ext(*entry, true, ent.filename); - snprintf(ent.attr , sizeof(ent.attr) , "%u %u %u %c%c" , entry->record_len , filesize / entry->record_len , entry->file_no , (entry->filetype & FT_WP_MASK) ? 'W' : ' ' , (entry->filetype & FT_HIDDEN_MASK) ? 'H' : ' '); - } - - - return IMGTOOLERR_SUCCESS; - } - - imgtoolerr_t hp85_tape_free_space(imgtool::partition &partition, uint64_t *size) - { - tape_state_t& state = get_tape_state(partition.image()); - tape_image_85& tape_image = get_tape_image(state); - unsigned used_recs = 0; - - const dir_entry_85 *entry = nullptr; - - for (unsigned i = 0; i < MAX_FILE_NO; i++) { - if (!tape_image.get_dir_entry(i, entry)) { - break; - } - // Ignore erased files - if (entry->filetype & FT_NULL_FILE_MASK) { - continue; - } - used_recs += entry->n_recs; - } - - if (used_recs >= MAX_N_RECORDS) { - *size = 0; - } else { - *size = (MAX_N_RECORDS - used_recs) * MAX_RECORD_SIZE; - } - - return IMGTOOLERR_SUCCESS; - } - - imgtoolerr_t hp85_tape_read_file(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &destf) - { - tape_state_t& state = get_tape_state(partition.image()); - tape_image_85& tape_image = get_tape_image(state); - - unsigned idx; - - if (!tape_image.find_file(filename , false , idx)) { - return IMGTOOLERR_FILENOTFOUND; - } - - const dir_entry_85 *ent = nullptr; - - tape_image.get_dir_entry(idx, ent); - - tape_image_85::sif_file_t file_data; - - if (!tape_image.load_sif_file(ent->file_no , file_data)) { - return IMGTOOLERR_READERROR; - } - - destf.write(file_data.data() , file_data.size()); - - return IMGTOOLERR_SUCCESS; - } - - imgtoolerr_t hp85_tape_write_file(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &sourcef, util::option_resolution *opts) - { - tape_state_t& state = get_tape_state(partition.image()); - tape_image_85& tape_image = get_tape_image(state); - - unsigned idx; - - if (tape_image.find_file(filename , true , idx)) { - // When overwriting a file, delete its old version first - tape_image.delete_dir_entry(idx); - } - - unsigned file_size = sourcef.size(); - - if (!file_size) { - return IMGTOOLERR_SUCCESS; - } - if (file_size > (MAX_N_RECORDS * MAX_RECORD_SIZE)) { - return IMGTOOLERR_NOSPACE; - } - - auto p_in_file = std::make_unique(); - - p_in_file->resize(file_size); - - if (sourcef.read(p_in_file->data() , file_size) != file_size) { - return IMGTOOLERR_READERROR; - } - - dir_entry_85 *ent = nullptr; - - if (!tape_image.alloc_new_file(ent , std::move(p_in_file))) { - return IMGTOOLERR_NOSPACE; - } - - char fname[ CHARS_PER_FNAME + 1 ]; - char ext[ CHARS_PER_EXT + 1 ]; - - tape_image_85::split_filename_and_ext(filename, fname, ext); - - char *dest = (char *)&ent->filename[ 0 ]; - char *dest0 = dest; - char *src = &fname[ 0 ]; - - while ((dest - dest0) < CHARS_PER_FNAME && *src != '\0') { - *dest++ = *src++; - } - while ((dest - dest0) < CHARS_PER_FNAME) { - *dest++ = ' '; - } - - int bpr = opts->lookup_int('B'); - if (bpr < 4) { - bpr = MAX_RECORD_SIZE; - } else if (bpr > file_size) { - util::stream_format(std::wcerr, L"BPR value too large, using %u\n", MAX_RECORD_SIZE); - bpr = MAX_RECORD_SIZE; - } - ent->record_len = (uint16_t)bpr; - - if (opts->lookup_int('T') == 0) { - // File type defaults to DATA if no extension is given or extension is invalid - ent->filetype = FT_DATA_MASK; - for (const auto& i : filetype_table) { - if (strcmp(i.ext , ext) == 0) { - ent->filetype = i.filetype_mask; - break; - } - } - } else { - ent->filetype = filetype_table[ opts->lookup_int('T') - 1 ].filetype_mask; - } - - if (!tape_image.finalize_allocation()) { - return IMGTOOLERR_NOSPACE; - } - - return IMGTOOLERR_SUCCESS; - } - - imgtoolerr_t hp85_tape_delete_file(imgtool::partition &partition, const char *filename) - { - tape_state_t& state = get_tape_state(partition.image()); - tape_image_85& tape_image = get_tape_image(state); - - unsigned idx; - - if (!tape_image.find_file(filename , true , idx)) { - return IMGTOOLERR_FILENOTFOUND; - } - - if (!tape_image.delete_dir_entry(idx)) { - return IMGTOOLERR_READERROR; - } - if (!tape_image.finalize_allocation()) { - return IMGTOOLERR_NOSPACE; - } - - return IMGTOOLERR_SUCCESS; - } -} -#define HP85_WRITEFILE_OPTSPEC "B[0]-32767;T[0]-3" - -OPTION_GUIDE_START(hp85_write_optguide) - OPTION_INT('B' , "bpr" , "Bytes per record") - OPTION_ENUM_START('T' , "ftype" , "File type") - OPTION_ENUM(0 , "auto" , "Automatic (\"DATA\" or by extension)") - OPTION_ENUM(1 , "P" , "PROG") - OPTION_ENUM(2 , "D" , "DATA") - OPTION_ENUM(3 , "B" , "BPGM") - OPTION_ENUM_END -OPTION_GUIDE_END - -void hp85_tape_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info) -{ - switch (state) { - case IMGTOOLINFO_STR_NAME: - strcpy(info->s = imgtool_temp_str(), "hp85_tape"); - break; - - case IMGTOOLINFO_STR_DESCRIPTION: - strcpy(info->s = imgtool_temp_str(), "HP85 tape image"); - break; - - case IMGTOOLINFO_STR_FILE: - strcpy(info->s = imgtool_temp_str(), __FILE__); - break; - - case IMGTOOLINFO_STR_FILE_EXTENSIONS: - strcpy(info->s = imgtool_temp_str(), "hti"); - break; - - case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES: - info->i = sizeof(tape_state_t); - break; - - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: - info->i = sizeof(dir_state_t); - break; - - case IMGTOOLINFO_PTR_OPEN: - info->open = hp85_tape_open; - break; - - case IMGTOOLINFO_PTR_CREATE: - info->create = hp85_tape_create; - break; - - case IMGTOOLINFO_PTR_CLOSE: - info->close = hp85_tape_close; - break; - - case IMGTOOLINFO_PTR_BEGIN_ENUM: - info->begin_enum = hp85_tape_begin_enum; - break; - - case IMGTOOLINFO_PTR_NEXT_ENUM: - info->next_enum = hp85_tape_next_enum; - break; - - case IMGTOOLINFO_PTR_FREE_SPACE: - info->free_space = hp85_tape_free_space; - break; - - case IMGTOOLINFO_PTR_READ_FILE: - info->read_file = hp85_tape_read_file; - break; - - case IMGTOOLINFO_PTR_WRITE_FILE: - info->write_file = hp85_tape_write_file; - break; - - case IMGTOOLINFO_PTR_DELETE_FILE: - info->delete_file = hp85_tape_delete_file; - break; - - case IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE: - info->writefile_optguide = &hp85_write_optguide; - break; - - case IMGTOOLINFO_STR_WRITEFILE_OPTSPEC: - strcpy(info->s = imgtool_temp_str(), HP85_WRITEFILE_OPTSPEC); - break; - } -} diff --git a/src/tools/imgtool/modules/hp9845_tape.cpp b/src/tools/imgtool/modules/hp9845_tape.cpp deleted file mode 100644 index 5254c26..0000000 --- a/src/tools/imgtool/modules/hp9845_tape.cpp +++ /dev/null @@ -1,1540 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:F. Ulivi -/********************************************************************* - - hp9845_tape.cpp - - HP-9845 tape format - - This imgtool module manipulates HTI files. These are image files - of the DC-100 tape cartridges that are simulated for the HP9845B - driver. - HP9845 filesystem for tapes has the following features: - * File names are 1 to 6 characters long. - * Case is significant in file names. - * There is no file "extension", file type is encoded separately - in file metadata. - * There are 8 file types. File type is encoded in 5 bits. - Only 8 out of the 32 possible values are valid. - * This module handles the file type as a fake file extension. - For example, a file named "TEST" having DATA type is get/put/shown - as "TEST.DATA". - * File type is deduced from host file extension when putting files - into image. File type can be overridden by the "ftype" option. - This table summarizes the file types. - - ftype Fake Type of file BASIC commands - switch extension for this file type - ======================================================== - U BKUP "Database backup" - No idea - D DATA Generic record-based data file - SAVE/GET/PRINT#/READ# - P PROG Program file (tokenized BASIC & other data) - STORE/LOAD - K KEYS KEY file (definition of soft keys) - STORE KEY/LOAD KEY - T BDAT Binary data file - ? - A ALL Full dump of system state - STORE ALL/LOAD ALL - B BPRG Binary program file - STORE BIN/LOAD BIN - O OPRM Option ROM specific file - ? - - * Files are always stored in units of 256-byte physical records. - * An important metadata of files is WPR: Words Per Record. This - is a numeric value that sets the length of each logical record of - the file (in units of 16-bit words). It defaults to 128 (i.e. - logical and physical records are the same thing). It can be - set by the "wpr" option when putting files into the image. - * There is no fragmentation map in the filesystem: each file - always occupy a contiguous set of physical records. This fact - could prevent the putting of a file into an image when there - is no single block of free records big enough to hold the file - even though the total amount of free space would be sufficient. - - Notes on commands - ================= - - **** dir command **** - The format of the "attr" part of file listing is as follows: - %c '*' if file has the protection bit set, else ' ' - %02x Hexadecimal value of file type (00-1f) - %c '?' if file type is not valid, else ' ' - %4u Number of logical records - %4u WPR * 2 (i.e. bytes per logical record) - %3u First physical record of file - - **** get command **** - A file can be extracted from an image with or without an explicit - extension. If an extension is given, it must match the one corresponding - to file type. - The "9845data" filter can be used on DATA files (see below). - - **** getall command **** - Files are extracted with their "fake" extension. - - **** put command **** - File type can be specified explicitly through the "ftype" option. - If this option is "auto" (the default), type is deduced from file - extension, if present. When extension is not given or it doesn't - match any known type, file type is set to "DATA". - WPR can be set through the "wpr" option. If it's 0 (the default), - WPR is set to 128. - The "9845data" filter can be used on DATA files (see below). - - **** del command **** - File extension is ignored, if present. - - "9845data" filter - ================= - - This filter can be applied to DATA files whose content is made - of strings only. BASIC programs that are saved with "SAVE" command - have this format. - This filter translates a DATA file into a standard ASCII text file - and viceversa. - Keep in mind that this translation is NOT lossless because all - non-ASCII & non printable characters are substituted with spaces. - This kind of characters must be removed because they may confuse - the line-by-line reading of file when translating in the opposite - direction. - The 9845 system has the capability to insert formatting characters - directly in the text strings to be displayed on screen. These - characters set things like inverse video or underline. - Turning a DATA file into a text file through this filter removes - these special characters. - -*********************************************************************/ -#include "imgtool.h" -#include "filter.h" - -#include "formats/hti_tape.h" -#include "formats/imageutl.h" - -#include "corefile.h" -#include "ioprocs.h" -#include "opresolv.h" - -#include -#include - - -// Constants -#define SECTOR_LEN 256 // Bytes in a sector -#define WORDS_PER_SECTOR (SECTOR_LEN / 2) // 16-bit words in a sector payload -#define SECTORS_PER_TRACK 426 // Sectors in a track -#define TRACKS_NO 2 // Number of tracks -#define TOT_SECTORS (SECTORS_PER_TRACK * TRACKS_NO) // Total number of sectors -#define DIR_WORD_0 0x0500 // First word of directories -#define DIR_WORD_1 0xffff // Second word of directories -#define DIR_LAST_WORD 0xffff // Last word of directories -#define FIRST_DIR_SECTOR 1 // First directory sector -#define SECTORS_PER_DIR 2 // Sectors per copy of directory -#define MAX_DIR_ENTRIES 42 // And the answer is.... the maximum number of entries in the directory! -#define DIR_COPIES 2 // Count of directory copies -#define CHARS_PER_FNAME 6 // Maximum characters in a filename -#define CHARS_PER_EXT 4 // Characters in file extension. Extension is encoded as file type, it's not actually stored in directory as characters. -#define CHARS_PER_FNAME_EXT (CHARS_PER_FNAME + 1 + CHARS_PER_EXT) // Characters in filename + extension -#define PAD_WORD 0xffff // Word value for padding -#define FIRST_FILE_SECTOR (FIRST_DIR_SECTOR + SECTORS_PER_DIR * DIR_COPIES) // First file sector -#define START_POS ((tape_pos_t)(72.25 * hti_format_t::ONE_INCH_POS)) // Start position on each track -#define DZ_WORDS 350 // Words in deadzone -#define IRG_SIZE hti_format_t::ONE_INCH_POS // Size of inter-record-gap: 1" -#define IFG_SIZE ((tape_pos_t)(2.5 * hti_format_t::ONE_INCH_POS)) // Size of inter-file-gap: 2.5" -#define HDR_W0_ZERO_MASK 0x4000 // Mask of zero bits in word 0 of header -#define RES_FREE_FIELD 0x2000 // Mask of "reserved free field" bit -#define FILE_ID_BIT 0x8000 // Mask of "file identifier" bit -#define SECTOR_IN_USE 0x1800 // Mask of "empty record indicator" (== !sector in use indicator) -#define SIF_FILE_NO 1 // SIF file # -#define SIF_FILE_NO_MASK 0x07ff // Mask of SIF file # -#define SIF_FREE_FIELD 0 // SIF free field -#define SIF_FREE_FIELD_MASK 0xf000 // Mask of SIF free field -#define BYTES_AVAILABLE 0xff00 // "bytes available" field = 256 -#define BYTES_AVAILABLE_MASK 0xff00 // Mask of "bytes available" field -#define BYTES_USED 0x00ff // "bytes used" field = 256 -#define BYTES_USED_MASK 0x00ff // Mask of "bytes used" field -#define FORMAT_SECT_SIZE ((tape_pos_t)(2.67 * hti_format_t::ONE_INCH_POS)) // Size of sectors including padding: 2.67" -#define PREAMBLE_WORD 0x0001 // Value of preamble word -#define WORDS_PER_HEADER_N_SECTOR (WORDS_PER_SECTOR + 5) -#define MIN_IRG_SIZE ((tape_pos_t)(16 * 1024)) // Minimum size of IRG gaps: 0.017" - -// File types -#define BKUP_FILETYPE 0 -#define BKUP_ATTR_STR "BKUP" -#define DATA_FILETYPE 1 -#define DATA_ATTR_STR "DATA" -#define PROG_FILETYPE 2 -#define PROG_ATTR_STR "PROG" -#define KEYS_FILETYPE 3 -#define KEYS_ATTR_STR "KEYS" -#define BDAT_FILETYPE 4 -#define BDAT_ATTR_STR "BDAT" -#define ALL_FILETYPE 5 -#define ALL_ATTR_STR "ALL" -#define BPRG_FILETYPE 6 -#define BPRG_ATTR_STR "BPRG" -#define OPRM_FILETYPE 7 -#define OPRM_ATTR_STR "OPRM" - -// Record type identifiers -#define REC_TYPE_EOR 0x1e // End-of-record -#define REC_TYPE_FULLSTR 0x3c // A whole (un-split) string -#define REC_TYPE_EOF 0x3e // End-of-file -#define REC_TYPE_1STSTR 0x1c // First part of a string -#define REC_TYPE_MIDSTR 0x0c // Middle part(s) of a string -#define REC_TYPE_ENDSTR 0x2c // Last part of a string - -// End-of-lines -#define EOLN (CRLF == 1 ? "\r" : (CRLF == 2 ? "\n" : (CRLF == 3 ? "\r\n" : NULL))) - -// Words stored on tape -using tape_word_t = hti_format_t::tape_word_t; - -// Tape position, 1 unit = 1 inch / (968 * 1024) -using tape_pos_t = hti_format_t::tape_pos_t; - -/******************************************************************************** - * Directory entries - ********************************************************************************/ -typedef struct { - uint8_t filename[ CHARS_PER_FNAME ]; // Filename (left justified, 0 padded on the right) - bool protection; // File protection - uint8_t filetype; // File type (00-1f) - uint16_t filepos; // File position (# of 1st sector) - uint16_t n_recs; // Number of records - uint16_t wpr; // Word-per-record - unsigned n_sects; // Count of sectors -} dir_entry_t; - -/******************************************************************************** - * Tape image - ********************************************************************************/ -class tape_image_t { -public: - tape_image_t(void); - - bool is_dirty(void) const { return dirty; } - - void format_img(void); - - imgtoolerr_t load_from_file(imgtool::stream *stream); - imgtoolerr_t save_to_file(imgtool::stream *stream); - - unsigned free_sectors(void) const; - - void set_sector(unsigned s_no , const tape_word_t *s_data); - void unset_sector(unsigned s_no); - bool get_sector(unsigned s_no , tape_word_t *s_data); - - bool get_dir_entry(unsigned idx , const dir_entry_t*& entry) const; - bool find_file(const char *filename , bool ignore_ext , unsigned& idx) const; - - void delete_dir_entry(unsigned idx); - - bool find_free_block(unsigned blocks , unsigned& first_s) const; - - bool alloc_new_file(unsigned blocks , dir_entry_t*& entry); - - static void tape_word_to_bytes(tape_word_t w , uint8_t& bh , uint8_t& bl); - static void bytes_to_tape_word(uint8_t bh , uint8_t bl , tape_word_t& w); - - static void get_filename_and_ext(const dir_entry_t& ent , bool inc_ext , char *out , bool& qmark); - static void split_filename_and_ext(const char *filename , char *fname , char *ext); - -private: - bool dirty; - // Tape image - tape_word_t img[ TOT_SECTORS ][ WORDS_PER_SECTOR ]; - // Map of sectors in use - std::bitset alloc_map; - // Directory - std::vector dir; - - static void wipe_sector(tape_word_t *s); - void dump_dir_sect(const tape_word_t *dir_sect , unsigned dir_sect_idx); - void fill_and_dump_dir_sect(tape_word_t *dir_sect , unsigned& idx , unsigned& dir_sect_idx , tape_word_t w) ; - void encode_dir(void); - bool read_sector_words(unsigned& sect_no , unsigned& sect_idx , size_t word_no , tape_word_t *out) const; - static bool filename_char_check(uint8_t c); - static bool filename_check(const uint8_t *filename); - bool decode_dir(void); - void save_words(hti_format_t& img , unsigned track , tape_pos_t& pos , const tape_word_t *block , unsigned block_len); - static tape_word_t checksum(const tape_word_t *block , unsigned block_len); -}; - -/******************************************************************************** - * Image state - ********************************************************************************/ -typedef struct { - imgtool::stream *stream; - tape_image_t *img; -} tape_state_t; - -/******************************************************************************** - * Directory enumeration - ********************************************************************************/ -typedef struct { - unsigned dir_idx; -} dir_state_t; - -/******************************************************************************** - * Internal functions - ********************************************************************************/ -tape_image_t::tape_image_t(void) - : dirty(false) -{ -} - -void tape_image_t::format_img(void) -{ - // Deallocate all sectors - alloc_map.reset(); - - // Create an empty directory - dir.clear(); - - dirty = true; -} - -imgtoolerr_t tape_image_t::load_from_file(imgtool::stream *stream) -{ - hti_format_t inp_image; - inp_image.set_image_format(hti_format_t::HTI_DELTA_MOD_16_BITS); - - 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; - for (unsigned track = 0; track < TRACKS_NO; track++ , last_sector_on_track += SECTORS_PER_TRACK) { - tape_pos_t pos = 0; - // Loader state: - // 0 Wait for DZ - // 1 Wait for sector data - // 2 Wait for gap - unsigned state = 0; - - while (exp_sector != last_sector_on_track) { - switch (state) { - case 0: - case 1: - { - hti_format_t::track_iterator_t it; - - if (!inp_image.next_data(track , pos , true , false , it)) { - // No more data on tape - return IMGTOOLERR_CORRUPTIMAGE; - } - if (state == 1) { - // Extract record data - - // The top 8 bits are ignored by TACO when aligning with preamble - unsigned bit_idx = 7; - if (!inp_image.sync_with_record(track , it , bit_idx)) { - // Couldn't align - return IMGTOOLERR_CORRUPTIMAGE; - } - tape_word_t buffer[ WORDS_PER_HEADER_N_SECTOR ]; - for (unsigned i = 0; i < WORDS_PER_HEADER_N_SECTOR; i++) { - auto res = inp_image.next_word(track , it , bit_idx , buffer[ i ]); - if (res != hti_format_t::ADV_CONT_DATA) { - return IMGTOOLERR_CORRUPTIMAGE; - } - } - if (buffer[ 3 ] != checksum(&buffer[ 0 ], 3) || - buffer[ 4 + WORDS_PER_SECTOR ] != checksum(&buffer[ 4 ], WORDS_PER_SECTOR)) { - return IMGTOOLERR_CORRUPTIMAGE; - } - // Check record content - if (exp_sector != (buffer[ 1 ] & 0xfff)) { - return IMGTOOLERR_CORRUPTIMAGE; - } - if (((buffer[ 0 ] & FILE_ID_BIT) != 0) != (exp_sector == 0)) { - return IMGTOOLERR_CORRUPTIMAGE; - } - if ((buffer[ 0 ] & (HDR_W0_ZERO_MASK | RES_FREE_FIELD | SIF_FILE_NO_MASK)) != (RES_FREE_FIELD | SIF_FILE_NO)) { - return IMGTOOLERR_CORRUPTIMAGE; - } - if ((buffer[ 1 ] & SIF_FREE_FIELD_MASK) != SIF_FREE_FIELD) { - return IMGTOOLERR_CORRUPTIMAGE; - } - bool in_use = (buffer[ 0 ] & SECTOR_IN_USE) != 0; - if ((buffer[ 2 ] & BYTES_AVAILABLE_MASK) != BYTES_AVAILABLE || - (in_use && (buffer[ 2 ] & BYTES_USED_MASK) != BYTES_USED) || - (!in_use && (buffer[ 2 ] & BYTES_USED_MASK) != 0)) { - return IMGTOOLERR_CORRUPTIMAGE; - } - if (in_use) { - set_sector(exp_sector, &buffer[ 4 ]); - } else { - unset_sector(exp_sector); - } - exp_sector++; - } - pos = it->first; - state = 2; - } - break; - - case 2: - // Find next gap - if (!inp_image.next_gap(track , pos , true , MIN_IRG_SIZE)) { - return IMGTOOLERR_CORRUPTIMAGE; - } - state = 1; - break; - - } - } - } - - if (!decode_dir()) { - return IMGTOOLERR_CORRUPTDIR; - } - - dirty = false; - - return IMGTOOLERR_SUCCESS; -} - -void tape_image_t::save_words(hti_format_t& img , unsigned track , tape_pos_t& pos , const tape_word_t *block , unsigned block_len) -{ - // Preamble - tape_pos_t length; - img.write_word(track , pos , PREAMBLE_WORD , length); - pos += length; - // Words - for (unsigned i = 0; i < block_len; i++) { - img.write_word(track , pos , *block++ , length); - pos += length; - } -} - -tape_word_t tape_image_t::checksum(const tape_word_t *block , unsigned block_len) -{ - tape_word_t csum = 0; - for (unsigned i = 0; i < block_len; i++) { - csum += *block++; - } - return csum & 0xffff; -} - -imgtoolerr_t tape_image_t::save_to_file(imgtool::stream *stream) -{ - // Encode copies of directory into sectors - encode_dir(); - - // Store sectors into image - hti_format_t out_image; - - unsigned rec_no = 0; - for (unsigned track = 0; track < TRACKS_NO; track++) { - tape_pos_t pos = START_POS; - - // Start of either track - // Deadzone + 1" of gap - tape_word_t deadzone[ DZ_WORDS ]; - for (auto& dz : deadzone) { - dz = PAD_WORD; - } - save_words(out_image, track, pos, deadzone, DZ_WORDS); - pos += IRG_SIZE; - - for (unsigned i = 0; i < SECTORS_PER_TRACK; i++ , rec_no++) { - bool in_use = alloc_map[ rec_no ]; - // Sector header - tape_word_t sector[ WORDS_PER_HEADER_N_SECTOR ]; - - // Header word 0: file identifier bit, reserved free-field bit, empty record indicator & file # - sector[ 0 ] = RES_FREE_FIELD | SIF_FILE_NO; - if (rec_no == 0) { - sector[ 0 ] |= FILE_ID_BIT; - } - if (in_use) { - sector[ 0 ] |= SECTOR_IN_USE; - } - // Header word 1: free-field & sector # - sector[ 1 ] = SIF_FREE_FIELD | rec_no; - // Header word 2: bytes available & bytes used - sector[ 2 ] = BYTES_AVAILABLE; - if (in_use) { - sector[ 2 ] |= BYTES_USED; - } - // Checksum of header - sector[ 3 ] = checksum(§or[ 0 ] , 3); - // Sector payload - if (in_use) { - memcpy(§or[ 4 ] , &img[ rec_no ][ 0 ] , SECTOR_LEN); - } else { - for (unsigned j = 4; j < (4 + WORDS_PER_SECTOR); j++) { - sector[ j ] = PAD_WORD; - } - } - // Checksum of payload - sector[ 4 + WORDS_PER_SECTOR ] = checksum(§or[ 4 ] , WORDS_PER_SECTOR); - - tape_pos_t start_pos = pos; - save_words(out_image, track, pos, sector, WORDS_PER_HEADER_N_SECTOR); - - // Pad sector up to FORMAT_SECT_SIZE - while ((pos - start_pos) < FORMAT_SECT_SIZE) { - tape_pos_t length; - out_image.write_word(track , pos , PAD_WORD , length); - pos += length; - } - - // Gap between sectors - if (rec_no == 0) { - pos += IFG_SIZE; - } else { - pos += IRG_SIZE; - } - } - } - - out_image.save_tape(*imgtool::stream_read_write(*stream, 0)); - - return IMGTOOLERR_SUCCESS; -} - -unsigned tape_image_t::free_sectors(void) const -{ - std::bitset tmp(alloc_map); - - // Reserve sectors that cannot be allocated to files - for (unsigned i = 0; i < FIRST_FILE_SECTOR; i++) { - tmp[ i ] = true; - } - - return TOT_SECTORS - tmp.count(); -} - -void tape_image_t::set_sector(unsigned s_no , const tape_word_t *s_data) -{ - if (s_no < TOT_SECTORS) { - memcpy(&img[ s_no ][ 0 ] , s_data , SECTOR_LEN); - alloc_map.set(s_no); - dirty = true; - } -} - -void tape_image_t::unset_sector(unsigned s_no) -{ - if (s_no < TOT_SECTORS) { - alloc_map.reset(s_no); - dirty = true; - } -} - -bool tape_image_t::get_sector(unsigned s_no , tape_word_t *s_data) -{ - if (s_no < TOT_SECTORS && alloc_map[ s_no ]) { - memcpy(s_data , &img[ s_no ][ 0 ] , SECTOR_LEN); - return true; - } else { - return false; - } -} - -bool tape_image_t::get_dir_entry(unsigned idx , const dir_entry_t*& entry) const -{ - if (idx >= dir.size()) { - return false; - } else { - entry = &dir[ idx ]; - return true; - } -} - -bool tape_image_t::find_file(const char *filename , bool ignore_ext , unsigned& idx) const -{ - char fname[ CHARS_PER_FNAME_EXT + 1 ]; - char ext[ CHARS_PER_EXT + 1 ]; - - split_filename_and_ext(filename, fname, ext); - - bool has_ext = !ignore_ext && *ext != '\0'; - - if (has_ext) { - strcat(fname , "."); - strcat(fname , ext); - } - - for (auto i = dir.cbegin(); i < dir.cend(); i++) { - char full_fname[ CHARS_PER_FNAME_EXT + 1 ]; - bool qmark; - - get_filename_and_ext(*i, has_ext, full_fname, qmark); - - if (strcmp(fname , full_fname) == 0) { - idx = i - dir.cbegin(); - return true; - } - } - - return false; -} - -void tape_image_t::delete_dir_entry(unsigned idx) -{ - const dir_entry_t& ent = dir[ idx ]; - - // Release all sectors of file - for (unsigned i = ent.filepos; i < ent.filepos + ent.n_sects; i++) { - unset_sector(i); - } - - dir.erase(dir.begin() + idx); - dirty = true; -} - -bool tape_image_t::find_free_block(unsigned blocks , unsigned& first_s) const -{ - if (blocks >= (TOT_SECTORS - FIRST_FILE_SECTOR)) { - return false; - } - - std::bitset scanner; - - for (unsigned i = FIRST_FILE_SECTOR; i < (FIRST_FILE_SECTOR + blocks); i++) { - scanner[ i ] = true; - } - - for (unsigned i = FIRST_FILE_SECTOR; i <= (TOT_SECTORS - blocks); i++) { - std::bitset tmp_map(alloc_map & scanner); - if (tmp_map.none()) { - first_s = i; - return true; - } - scanner <<= 1; - } - - return false; -} - -bool tape_image_t::alloc_new_file(unsigned blocks , dir_entry_t*& entry) -{ - if (dir.size() >= MAX_DIR_ENTRIES) { - return false; - } - - dir_entry_t new_entry; - - memset(&new_entry.filename[ 0 ] , 0 , sizeof(new_entry.filename)); - new_entry.protection = 0; - new_entry.filetype = 0; - new_entry.n_recs = 0; - new_entry.wpr = 0; - - unsigned first_s; - - if (!find_free_block(blocks, first_s)) { - return false; - } - - new_entry.filepos = (uint16_t)first_s; - new_entry.n_sects = blocks; - - dir.push_back(new_entry); - entry = &dir.back(); - dirty = true; - - return true; -} - -void tape_image_t::split_filename_and_ext(const char *filename , char *fname , char *ext) -{ - char *fname_fence = fname + CHARS_PER_FNAME; - - while (fname < fname_fence && *filename != '\0' && *filename != '.') { - *fname++ = *filename++; - } - - *fname = '\0'; - - while (*filename != '\0' && *filename != '.') { - filename++; - } - - if (*filename == '\0') { - *ext = '\0'; - } else { - filename++; - strncpy(ext , filename , CHARS_PER_EXT); - ext[ CHARS_PER_EXT ] = '\0'; - } -} - -void tape_image_t::wipe_sector(tape_word_t *s) -{ - for (unsigned i = 0; i < WORDS_PER_SECTOR; i++) { - s[ i ] = PAD_WORD; - } -} - -void tape_image_t::tape_word_to_bytes(tape_word_t w , uint8_t& bh , uint8_t& bl) -{ - bh = (uint8_t)(w >> 8); - bl = (uint8_t)(w & 0xff); -} - -void tape_image_t::bytes_to_tape_word(uint8_t bh , uint8_t bl , tape_word_t& w) -{ - w = ((tape_word_t)bh << 8) | ((tape_word_t)bl); -} - -void tape_image_t::dump_dir_sect(const tape_word_t *dir_sect , unsigned dir_sect_idx) -{ - for (unsigned i = 0; i < DIR_COPIES; i++) { - set_sector(FIRST_DIR_SECTOR + i * SECTORS_PER_DIR + dir_sect_idx, dir_sect); - } -} - -void tape_image_t::fill_and_dump_dir_sect(tape_word_t *dir_sect , unsigned& idx , unsigned& dir_sect_idx , tape_word_t w) -{ - // Dump sector once it's full - if (idx >= WORDS_PER_SECTOR) { - dump_dir_sect(dir_sect, dir_sect_idx); - wipe_sector(dir_sect); - idx = 0; - dir_sect_idx++; - } - dir_sect[ idx++ ] = w; -} - -void tape_image_t::encode_dir(void) -{ - tape_word_t dir_sect[ WORDS_PER_SECTOR ]; - - wipe_sector(dir_sect); - - unsigned idx = 0; - unsigned dir_sect_idx = 0; - - fill_and_dump_dir_sect(dir_sect, idx, dir_sect_idx, DIR_WORD_0); - fill_and_dump_dir_sect(dir_sect, idx, dir_sect_idx, DIR_WORD_1); - - for (const dir_entry_t& ent : dir) { - tape_word_t tmp; - - // Filename - bytes_to_tape_word(ent.filename[ 0 ], ent.filename[ 1 ], tmp); - fill_and_dump_dir_sect(dir_sect, idx, dir_sect_idx, tmp); - bytes_to_tape_word(ent.filename[ 2 ], ent.filename[ 3 ], tmp); - fill_and_dump_dir_sect(dir_sect, idx, dir_sect_idx, tmp); - bytes_to_tape_word(ent.filename[ 4 ], ent.filename[ 5 ], tmp); - fill_and_dump_dir_sect(dir_sect, idx, dir_sect_idx, tmp); - // Protection, file type & file position - tmp = ((tape_word_t)ent.filetype << 10) | (tape_word_t)ent.filepos; - if (ent.protection) { - tmp |= 0x8000; - } - fill_and_dump_dir_sect(dir_sect, idx, dir_sect_idx, tmp); - // File size (# of records) - fill_and_dump_dir_sect(dir_sect, idx, dir_sect_idx, ent.n_recs); - // Words per record - fill_and_dump_dir_sect(dir_sect, idx, dir_sect_idx, ent.wpr); - } - - // Terminator - fill_and_dump_dir_sect(dir_sect, idx, dir_sect_idx, DIR_LAST_WORD); - - // Dump last partial sector - dump_dir_sect(dir_sect, dir_sect_idx); - - // Unset unused sectors - for (unsigned i = dir_sect_idx + 1; i < SECTORS_PER_DIR; i++) { - for (unsigned j = 0; j < DIR_COPIES; j++) { - unset_sector(FIRST_DIR_SECTOR + i + j * SECTORS_PER_DIR); - } - } -} - -bool tape_image_t::read_sector_words(unsigned& sect_no , unsigned& sect_idx , size_t word_no , tape_word_t *out) const -{ - while (word_no > 0) { - if (sect_idx >= WORDS_PER_SECTOR) { - sect_idx = 0; - sect_no++; - if (sect_no >= TOT_SECTORS || !alloc_map[ sect_no ]) { - return false; - } - } - *out++ = img[ sect_no ][ sect_idx ]; - sect_idx++; - word_no--; - } - - return true; -} - -bool tape_image_t::filename_char_check(uint8_t c) -{ - // Colons and quotation marks are forbidden in file names - return 0x20 < c && c < 0x7f && c != ':' && c != '"'; -} - -bool tape_image_t::filename_check(const uint8_t *filename) -{ - bool ended = false; - - for (unsigned i = 0; i < 6; i++) { - uint8_t c = *filename++; - - if (ended) { - if (c != 0) { - return false; - } - } else if (c == 0) { - ended = true; - } else if (!filename_char_check(c)) { - return false; - } - } - - return true; -} - -static const char *const filetype_attrs[] = { - BKUP_ATTR_STR, // 0 - DATA_ATTR_STR, // 1 - PROG_ATTR_STR, // 2 - KEYS_ATTR_STR, // 3 - BDAT_ATTR_STR, // 4 - ALL_ATTR_STR, // 5 - BPRG_ATTR_STR, // 6 - OPRM_ATTR_STR // 7 -}; - -void tape_image_t::get_filename_and_ext(const dir_entry_t& ent , bool inc_ext , char *out , bool& qmark) -{ - strncpy(&out[ 0 ] , (const char*)&ent.filename[ 0 ] , CHARS_PER_FNAME); - out[ CHARS_PER_FNAME ] = '\0'; - - // Decode filetype - uint8_t type_low = ent.filetype & 7; - uint8_t type_hi = (ent.filetype >> 3) & 3; - - const char *filetype_str = filetype_attrs[ type_low ]; - - // Same logic used by hp9845b to add a question mark next to filetype - qmark = (type_low == DATA_FILETYPE && type_hi == 3) || - (type_low != DATA_FILETYPE && type_hi != 2); - - if (inc_ext) { - strcat(out , "."); - strcat(out , filetype_str); - } -} - -bool tape_image_t::decode_dir(void) -{ - unsigned sect_no = FIRST_DIR_SECTOR - 1; - unsigned sect_idx = SECTOR_LEN; - - dir.clear(); - - tape_word_t tmp; - - if (!read_sector_words(sect_no, sect_idx, 1, &tmp)) { - return false; - } - if (tmp != DIR_WORD_0) { - return false; - } - if (!read_sector_words(sect_no, sect_idx, 1, &tmp)) { - return false; - } - if (tmp != DIR_WORD_1) { - return false; - } - - // This is to check for overlapping files - std::bitset sect_in_use; - - while (1) { - if (!read_sector_words(sect_no, sect_idx, 1, &tmp)) { - return false; - } - if (tmp == DIR_LAST_WORD) { - // End of directory - break; - } - - if (dir.size() >= MAX_DIR_ENTRIES) { - // Too many entries - return false; - } - - dir_entry_t new_entry; - - // Filename - tape_word_to_bytes(tmp, new_entry.filename[ 0 ], new_entry.filename[ 1 ]); - if (!read_sector_words(sect_no, sect_idx, 1, &tmp)) { - return false; - } - tape_word_to_bytes(tmp, new_entry.filename[ 2 ], new_entry.filename[ 3 ]); - if (!read_sector_words(sect_no, sect_idx, 1, &tmp)) { - return false; - } - tape_word_to_bytes(tmp, new_entry.filename[ 4 ], new_entry.filename[ 5 ]); - if (!filename_check(new_entry.filename)) { - return false; - } - - // Protection, file type & file position - if (!read_sector_words(sect_no, sect_idx, 1, &tmp)) { - return false; - } - new_entry.protection = (tmp & 0x8000) != 0; - new_entry.filetype = ((tmp >> 10) & 0x1f); - new_entry.filepos = tmp & 0x3ff; - if (new_entry.filepos < FIRST_FILE_SECTOR || new_entry.filepos >= TOT_SECTORS) { - return false; - } - - // File size (# of records) - if (!read_sector_words(sect_no, sect_idx, 1, &tmp)) { - return false; - } - new_entry.n_recs = tmp; - - // Words per record - if (!read_sector_words(sect_no, sect_idx, 1, &tmp)) { - return false; - } - new_entry.wpr = tmp; - if (new_entry.wpr < 1) { - return false; - } - - new_entry.n_sects = ((unsigned)new_entry.wpr * new_entry.n_recs * 2 + SECTOR_LEN - 1) / SECTOR_LEN; - if (new_entry.n_sects < 1 || (new_entry.n_sects + new_entry.filepos) > TOT_SECTORS) { - return false; - } - - for (unsigned i = new_entry.filepos; i < new_entry.n_sects + new_entry.filepos; i++) { - if (sect_in_use[ i ]) { - return false; - } - sect_in_use[ i ] = true; - } - - dir.push_back(new_entry); - } - - // Check for inconsistency between alloc_map & sect_in_use - for (unsigned i = 0; i < FIRST_FILE_SECTOR; i++) { - sect_in_use[ i ] = alloc_map[ i ]; - } - - std::bitset tmp_map(~alloc_map & sect_in_use); - if (tmp_map.any()) { - // There is at least 1 sector that is in use by a file but it's empty/unallocated - return false; - } - - alloc_map = sect_in_use; - - return true; -} - -static tape_state_t& get_tape_state(imgtool::image &img) -{ - tape_state_t *ts = (tape_state_t*)img.extra_bytes(); - - return *ts; -} - -static tape_image_t& get_tape_image(tape_state_t& ts) -{ - if (ts.img == nullptr) { - ts.img = new tape_image_t; - } - - return *(ts.img); -} - -/******************************************************************************** - * Imgtool functions - ********************************************************************************/ -static imgtoolerr_t hp9845_tape_open(imgtool::image &image, imgtool::stream::ptr &&stream) -{ - tape_state_t& state = get_tape_state(image); - - state.stream = stream.release(); - - tape_image_t& tape_image = get_tape_image(state); - - imgtoolerr_t err = tape_image.load_from_file(state.stream); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t hp9845_tape_create(imgtool::image &image, imgtool::stream::ptr &&stream, util::option_resolution *opts) -{ - tape_state_t& state = get_tape_state(image); - - state.stream = stream.release(); - - tape_image_t& tape_image = get_tape_image(state); - - tape_image.format_img(); - - return IMGTOOLERR_SUCCESS; -} - -static void hp9845_tape_close(imgtool::image &image) -{ - tape_state_t& state = get_tape_state(image); - tape_image_t& tape_image = get_tape_image(state); - - if (tape_image.is_dirty()) { - (void)tape_image.save_to_file(state.stream); - } - - delete state.stream; - - // Free tape_image - delete &tape_image; -} - -static imgtoolerr_t hp9845_tape_begin_enum (imgtool::directory &enumeration, const char *path) -{ - dir_state_t *ds = (dir_state_t*)enumeration.extra_bytes(); - - ds->dir_idx = 0; - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t hp9845_tape_next_enum (imgtool::directory &enumeration, imgtool_dirent &ent) -{ - tape_state_t& state = get_tape_state(enumeration.image()); - tape_image_t& tape_image = get_tape_image(state); - dir_state_t *ds = (dir_state_t*)enumeration.extra_bytes(); - - const dir_entry_t *entry = nullptr; - - if (!tape_image.get_dir_entry(ds->dir_idx, entry)) { - ent.eof = 1; - } else { - ds->dir_idx++; - - bool qmark; - - tape_image_t::get_filename_and_ext(*entry, true, ent.filename, qmark); - - // "filename" and "attr" fields try to look like the output of the "CAT" command - snprintf(ent.attr , sizeof(ent.attr) , "%c %02x%c %4u %4u %3u" , entry->protection ? '*' : ' ' , entry->filetype , qmark ? '?' : ' ' , entry->n_recs , entry->wpr * 2 , entry->filepos); - - ent.filesize = entry->n_sects * SECTOR_LEN; - } - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t hp9845_tape_free_space(imgtool::partition &partition, uint64_t *size) -{ - tape_state_t& state = get_tape_state(partition.image()); - tape_image_t& tape_image = get_tape_image(state); - - *size = tape_image.free_sectors() * SECTOR_LEN; - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t hp9845_tape_read_file(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &destf) -{ - tape_state_t& state = get_tape_state(partition.image()); - tape_image_t& tape_image = get_tape_image(state); - - unsigned idx; - - if (!tape_image.find_file(filename , false , idx)) { - return IMGTOOLERR_FILENOTFOUND; - } - - const dir_entry_t *ent = nullptr; - - tape_image.get_dir_entry(idx, ent); - - unsigned sect_no = ent->filepos; - unsigned n_sects = ent->n_sects; - tape_word_t buff_w[ WORDS_PER_SECTOR ]; - uint8_t buff_b[ SECTOR_LEN ]; - - while (n_sects--) { - if (!tape_image.get_sector(sect_no++, &buff_w[ 0 ])) { - return IMGTOOLERR_READERROR; - } - for (unsigned i = 0; i < WORDS_PER_SECTOR; i++) { - tape_image_t::tape_word_to_bytes(buff_w[ i ], buff_b[ i * 2 ], buff_b[ i * 2 + 1 ]); - } - - destf.write(buff_b , SECTOR_LEN); - } - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t hp9845_tape_write_file(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &sourcef, util::option_resolution *opts) -{ - tape_state_t& state = get_tape_state(partition.image()); - tape_image_t& tape_image = get_tape_image(state); - - unsigned idx; - - if (tape_image.find_file(filename , true , idx)) { - // When overwriting a file, delete its old version first - tape_image.delete_dir_entry(idx); - } - - unsigned blocks = (unsigned)((sourcef.size() + SECTOR_LEN - 1) / SECTOR_LEN); - - if (!blocks) { - fprintf(stderr , "Null file, not writing..\n"); - return IMGTOOLERR_SUCCESS; - } - - dir_entry_t *ent = nullptr; - - if (!tape_image.alloc_new_file(blocks, ent)) { - return IMGTOOLERR_NOSPACE; - } - - unsigned s_no = ent->filepos; - - char fname[ CHARS_PER_FNAME + 1 ]; - char ext[ CHARS_PER_EXT + 1 ]; - - tape_image_t::split_filename_and_ext(filename, fname, ext); - - strncpy((char*)&ent->filename[ 0 ] , fname , CHARS_PER_FNAME); - - for (unsigned i = 0; i < blocks; i++) { - tape_word_t buff_w[ WORDS_PER_SECTOR ]; - uint8_t buff_b[ SECTOR_LEN ]; - - memset(&buff_b[ 0 ] , 0 , sizeof(buff_b)); - - if (sourcef.read(buff_b , SECTOR_LEN) != SECTOR_LEN && i != (blocks - 1)) { - return IMGTOOLERR_READERROR; - } - for (unsigned j = 0; j < WORDS_PER_SECTOR; j++) { - tape_image_t::bytes_to_tape_word(buff_b[ 2 * j ], buff_b[ 2 * j + 1 ], buff_w[ j ]); - } - tape_image.set_sector(s_no, buff_w); - s_no++; - } - - int wpr = opts->lookup_int('W'); - if (wpr == 0) { - wpr = WORDS_PER_SECTOR; - } else if (wpr > (blocks * WORDS_PER_SECTOR)) { - fprintf(stderr , "WPR value too large, using %u\n" , WORDS_PER_SECTOR); - wpr = WORDS_PER_SECTOR; - } - ent->wpr = (uint16_t)wpr; - - ent->n_recs = (uint16_t)((blocks * WORDS_PER_SECTOR) / wpr); - - unsigned type_low; - - if (opts->lookup_int('T') == 0) { - // File type defaults to DATA if no extension is given or extension is invalid - type_low = DATA_FILETYPE; - for (unsigned i = 0; i < 8; i++) { - if (strcmp(filetype_attrs[ i ] , ext) == 0) { - type_low = i; - break; - } - } - } else { - type_low = opts->lookup_int('T') - 1; - } - - // See tape_image_t::get_filename_and_ext for the logic behind file type - if (type_low == DATA_FILETYPE) { - ent->filetype = (uint8_t)type_low + (1U << 3); - } else { - ent->filetype = (uint8_t)type_low + (2U << 3); - } - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t hp9845_tape_delete_file(imgtool::partition &partition, const char *filename) -{ - tape_state_t& state = get_tape_state(partition.image()); - tape_image_t& tape_image = get_tape_image(state); - - unsigned idx; - - if (!tape_image.find_file(filename , true , idx)) { - return IMGTOOLERR_FILENOTFOUND; - } - - tape_image.delete_dir_entry(idx); - - return IMGTOOLERR_SUCCESS; -} - -#define HP9845_WRITEFILE_OPTSPEC "W[0]-65535;T[0]-8" - -OPTION_GUIDE_START(hp9845_write_optguide) - OPTION_INT('W' , "wpr" , "Words per record") - OPTION_ENUM_START('T' , "ftype" , "File type") - OPTION_ENUM(0 , "auto" , "Automatic (\"DATA\" or by extension)") - OPTION_ENUM(1 , "U" , "BKUP") - OPTION_ENUM(2 , "D" , "DATA") - OPTION_ENUM(3 , "P" , "PROG") - OPTION_ENUM(4 , "K" , "KEYS") - OPTION_ENUM(5 , "T" , "BDAT") - OPTION_ENUM(6 , "A" , "ALL") - OPTION_ENUM(7 , "B" , "BPRG") - OPTION_ENUM(8 , "O" , "OPRM") - OPTION_ENUM_END -OPTION_GUIDE_END - -void hp9845_tape_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info) -{ - switch (state) { - case IMGTOOLINFO_STR_NAME: - strcpy(info->s = imgtool_temp_str(), "hp9845_tape"); - break; - - case IMGTOOLINFO_STR_DESCRIPTION: - strcpy(info->s = imgtool_temp_str(), "HP9845 tape image"); - break; - - case IMGTOOLINFO_STR_FILE: - strcpy(info->s = imgtool_temp_str(), __FILE__); - break; - - case IMGTOOLINFO_STR_FILE_EXTENSIONS: - strcpy(info->s = imgtool_temp_str(), "hti"); - break; - - case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES: - info->i = sizeof(tape_state_t); - break; - - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: - info->i = sizeof(dir_state_t); - break; - - case IMGTOOLINFO_PTR_OPEN: - info->open = hp9845_tape_open; - break; - - case IMGTOOLINFO_PTR_CREATE: - info->create = hp9845_tape_create; - break; - - case IMGTOOLINFO_PTR_CLOSE: - info->close = hp9845_tape_close; - break; - - case IMGTOOLINFO_PTR_BEGIN_ENUM: - info->begin_enum = hp9845_tape_begin_enum; - break; - - case IMGTOOLINFO_PTR_NEXT_ENUM: - info->next_enum = hp9845_tape_next_enum; - break; - - case IMGTOOLINFO_PTR_FREE_SPACE: - info->free_space = hp9845_tape_free_space; - break; - - case IMGTOOLINFO_PTR_READ_FILE: - info->read_file = hp9845_tape_read_file; - break; - - case IMGTOOLINFO_PTR_WRITE_FILE: - info->write_file = hp9845_tape_write_file; - break; - - case IMGTOOLINFO_PTR_DELETE_FILE: - info->delete_file = hp9845_tape_delete_file; - break; - - case IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE: - info->writefile_optguide = &hp9845_write_optguide; - break; - - case IMGTOOLINFO_STR_WRITEFILE_OPTSPEC: - strcpy(info->s = imgtool_temp_str(), HP9845_WRITEFILE_OPTSPEC); - break; - } -} - -/******************************************************************************** - * Filter functions - ********************************************************************************/ -static unsigned len_to_eor(imgtool::stream &inp) -{ - return SECTOR_LEN - (unsigned)(inp.tell() % SECTOR_LEN); -} - -static bool get_record_part(imgtool::stream &inp , void *buf , unsigned len) -{ - // Reading must never cross sector boundary - if (len > len_to_eor(inp)) { - return false; - } - - return inp.read(buf, len) == len; -} - -static bool dump_string(imgtool::stream &inp, imgtool::stream &out , unsigned len , bool add_eoln) -{ - uint8_t tmp[ SECTOR_LEN ]; - - if (!get_record_part(inp , tmp , len)) { - return false; - } - - // Sanitize string - for (unsigned i = 0; i < len; i++) { - if (!isascii(tmp[ i ]) || !isprint(tmp[ i ])) { - tmp[ i ] = ' '; - } - } - - out.write(tmp , len); - if (add_eoln) { - out.puts(EOLN); - } - - return true; -} - -static imgtoolerr_t hp9845data_read_file(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &destf) -{ - imgtool::stream::ptr inp_data; - imgtoolerr_t res; - uint8_t tmp[ 2 ]; - - inp_data = imgtool::stream::open_mem(NULL , 0); - if (!inp_data) - return IMGTOOLERR_OUTOFMEMORY; - - res = hp9845_tape_read_file(partition , filename , fork , *inp_data); - if (res != IMGTOOLERR_SUCCESS) - return res; - - inp_data->seek(0, SEEK_SET); - - uint16_t rec_type; - unsigned rec_len; - unsigned tmp_len; - unsigned accum_len = 0; - - do { - // Get record type - if (!get_record_part(*inp_data , tmp , 2)) { - return IMGTOOLERR_READERROR; - } - rec_type = (uint16_t)pick_integer_be(tmp , 0 , 2); - switch (rec_type) { - case REC_TYPE_EOR: - // End of record: just skip it - break; - - case REC_TYPE_FULLSTR: - // A string in a single piece - case REC_TYPE_1STSTR: - // First piece of a split string - case REC_TYPE_MIDSTR: - // Mid piece(s) of a split string - case REC_TYPE_ENDSTR: - // Closing piece of a split string - if (((rec_type == REC_TYPE_FULLSTR || rec_type == REC_TYPE_1STSTR) && accum_len > 0) || - ((rec_type == REC_TYPE_MIDSTR || rec_type == REC_TYPE_ENDSTR) && accum_len == 0)) { - fputs("Wrong sequence of string pieces\n" , stderr); - return IMGTOOLERR_CORRUPTFILE; - } - - if (!get_record_part(*inp_data , tmp , 2)) { - return IMGTOOLERR_READERROR; - } - tmp_len = (unsigned)pick_integer_be(tmp , 0 , 2); - - if (rec_type == REC_TYPE_FULLSTR || rec_type == REC_TYPE_1STSTR) { - accum_len = tmp_len; - } else if (tmp_len != accum_len) { - fputs("Wrong length of string piece\n" , stderr); - return IMGTOOLERR_CORRUPTFILE; - } - - if (rec_type == REC_TYPE_FULLSTR || rec_type == REC_TYPE_ENDSTR) { - rec_len = accum_len; - } else { - rec_len = std::min(accum_len , len_to_eor(*inp_data)); - } - if (!dump_string(*inp_data , destf , rec_len , rec_type == REC_TYPE_FULLSTR || rec_type == REC_TYPE_ENDSTR)) { - return IMGTOOLERR_READERROR; - } - if (rec_len & 1) { - // Keep length of string pieces even - get_record_part(*inp_data , tmp , 1); - } - accum_len -= rec_len; - break; - - case REC_TYPE_EOF: - // End of file - break; - - default: - fprintf(stderr , "Unknown record type (%04x)\n" , rec_type); - return IMGTOOLERR_CORRUPTFILE; - } - } while (rec_type != REC_TYPE_EOF); - - return IMGTOOLERR_SUCCESS; -} - -static bool split_string_n_dump(const char *s , imgtool::stream &dest) -{ - unsigned s_len = strlen(s); - uint16_t rec_type = REC_TYPE_1STSTR; - uint8_t tmp[ 4 ]; - bool at_least_one = false; - - while (1) { - 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); - while (free_len) { - if (dest.write(tmp , 2) != 2) { - return false; - } - free_len -= 2; - } - } else { - unsigned s_part_len = std::min(free_len - 4 , s_len); - if (s_part_len == s_len) { - // 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); - if (dest.write(tmp , 4) != 4 || - dest.write(s, s_part_len) != s_part_len) { - return false; - } - rec_type = REC_TYPE_MIDSTR; - s_len -= s_part_len; - s += s_part_len; - at_least_one = true; - } - } - - place_integer_be(tmp , 0 , 2 , at_least_one ? REC_TYPE_ENDSTR : REC_TYPE_FULLSTR); - place_integer_be(tmp , 2 , 2 , s_len); - if (dest.write(tmp , 4) != 4 || - dest.write(s , s_len) != s_len) { - return false; - } - if (s_len & 1) { - tmp[ 0 ] = 0; - if (dest.write(tmp , 1) != 1) { - return false; - } - } - return true; -} - -static imgtoolerr_t hp9845data_write_file(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &sourcef, util::option_resolution *opts) -{ - imgtool::stream::ptr out_data; - - out_data = imgtool::stream::open_mem(NULL , 0); - if (!out_data) - return IMGTOOLERR_OUTOFMEMORY; - - while (1) { - char line[ 256 ]; - - // Read input file one line at time - if (sourcef.core_file()->gets(line , sizeof(line)) == nullptr) { - // EOF - break; - } - line[ sizeof(line) - 1 ] = '\0'; - - // Strip space and non-ASCII characters from the end of the line - size_t line_len = strlen(line); - char *p = &line[ line_len ]; - while (p != line) { - char c = *(--p); - if (isascii(c) && !isspace(c)) { - break; - } - *p = '\0'; - } - - // Ignore empty lines - if (p == line) { - continue; - } - - if (!split_string_n_dump(line, *out_data)) { - return IMGTOOLERR_WRITEERROR; - } - } - - // 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); - - while (free_len) { - if (out_data->write(tmp , 2 ) != 2) { - return IMGTOOLERR_WRITEERROR; - } - free_len -= 2; - } - - out_data->seek(0 , SEEK_SET); - - imgtoolerr_t res = hp9845_tape_write_file(partition, filename, fork, *out_data, opts); - - return res; -} - -void filter_hp9845data_getinfo(uint32_t state, union filterinfo *info) -{ - switch (state) { - case FILTINFO_PTR_READFILE: - info->read_file = hp9845data_read_file; - break; - - case FILTINFO_PTR_WRITEFILE: - info->write_file = hp9845data_write_file; - break; - - case FILTINFO_STR_NAME: - info->s = "9845data"; - break; - - case FILTINFO_STR_HUMANNAME: - info->s = "HP9845 text-only DATA files"; - break; - - case FILTINFO_STR_EXTENSION: - info->s = "txt"; - break; - } -} diff --git a/src/tools/imgtool/modules/mac.cpp b/src/tools/imgtool/modules/mac.cpp deleted file mode 100644 index a6eadf4..0000000 --- a/src/tools/imgtool/modules/mac.cpp +++ /dev/null @@ -1,6443 +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 "imgtool.h" -#include "charconv.h" -#include "iflopimg.h" - -#include "macutil.h" - -#include "formats/ap_dsk35.h" -#include "formats/imageutl.h" -#include "opresolv.h" - -#include -#include -#include -#include -#include - -/* 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 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; il2_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; il2_img, i) == 0) - { - if (TAG_CHECKS) - { - /* optional check */ - if (image_get_tag_len(&fileref->l2_img->l1_img) == 12) - { - for (j=0; jl2_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; jl2_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; il2_img, i) == 0) - { /* found one free block */ - /* compute its length */ - extentBaseAB = i; - extentABlen = 0; - while ((il2_img, i) == 0)) - { - if (TAG_CHECKS) - { - /* optional check */ - if (image_get_tag_len(&fileref->l2_img->l1_img) == 12) - { - for (j=0; jl2_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; imfs.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; jl2_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; imfs.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; jl2_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; (il2_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; jl2_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; jl2_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; jl2_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> 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; itreeDepth; i++) - data_nodes[i].buf = NULL; /* required for function postlog to work should next loop fail */ - for (i=0; itreeDepth; 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 ((itreeDepth) && ((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 (itreeDepth) - { - /* 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; itreeDepth; 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 (totalNodes-map_count*8)) - run_bit_len = totalNodes-map_count*8; - for (i=0; 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; itreeDepth; 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; inode_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, std::size(buffer), image->u.mfs.volname); - break; - - case L2I_HFS: - mac_to_c_strncpy(buffer, std::size(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, std::size(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 = std::size(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, std::size(ent.filename), catrec_key->cName); -// concat_fname(ent.filename, &cur_name_head, std::size(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, std::size(ent.filename) - 1, ":"); - concat_fname(ent.filename, &cur_name_head, std::size(ent.filename) - 1, "???"); - - memmove(ent.filename, ent.filename+cur_name_head, std::size(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, std::size(ent.filename)-1, ":"); - concat_fname(ent.filename, &cur_name_head, std::size(ent.filename)-1, "???"); - - memmove(ent.filename, ent.filename+cur_name_head, std::size(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, std::size(ent.filename) - 1, ":"); - concat_fname(ent.filename, &cur_name_head, std::size(ent.filename) - 1, buf); - - /* extract parent directory ID */ - parID = get_UINT32BE(catrec_data->thread.parID); - } - memmove(ent.filename, ent.filename+cur_name_head, std::size(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 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 &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((std::size(attrs) - 1) - == std::size(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 b75ea3d..0000000 --- a/src/tools/imgtool/modules/macbin.cpp +++ /dev/null @@ -1,384 +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 "imgtool.h" -#include "filter.h" - -#include "macutil.h" - -#include "formats/imageutl.h" - -#include - - - -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 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 1838555..0000000 --- a/src/tools/imgtool/modules/macutil.cpp +++ /dev/null @@ -1,118 +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 "filter.h" - -#include "timeconv.h" - - -typedef util::arbitrary_clock > classic_mac_clock; - -//------------------------------------------------- -// mac_crack_time -//------------------------------------------------- - -imgtool::datetime mac_crack_time(uint32_t t) -{ - classic_mac_clock::duration d(t); - std::chrono::time_point 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 ce364f6..0000000 --- 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 "library.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 deleted file mode 100644 index 104e48b..0000000 --- a/src/tools/imgtool/modules/os9.cpp +++ /dev/null @@ -1,1241 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/**************************************************************************** - - os9.cpp - - CoCo OS-9 disk images - -****************************************************************************/ - -#include "imgtool.h" -#include "iflopimg.h" - -#include "formats/imageutl.h" -#include "formats/coco_dsk.h" -#include "opresolv.h" - -#include -#include - -enum creation_policy_t -{ - CREATE_NONE, - CREATE_FILE, - CREATE_DIR -}; - -struct os9_diskinfo -{ - uint32_t total_sectors; - uint32_t sectors_per_track; - uint32_t allocation_bitmap_bytes; - uint32_t cluster_size; - uint32_t root_dir_lsn; - uint32_t owner_id; - uint32_t attributes; - uint32_t disk_id; - uint32_t format_flags; - uint32_t bootstrap_lsn; - uint32_t bootstrap_size; - uint32_t sector_size; - - unsigned int sides : 2; - unsigned int double_density : 1; - unsigned int double_track : 1; - unsigned int quad_track_density : 1; - unsigned int octal_track_density : 1; - - char name[33]; - uint8_t allocation_bitmap[65536]; -}; - - -struct os9_fileinfo -{ - unsigned int directory : 1; - unsigned int non_sharable : 1; - unsigned int public_execute : 1; - unsigned int public_write : 1; - unsigned int public_read : 1; - unsigned int user_execute : 1; - unsigned int user_write : 1; - unsigned int user_read : 1; - - uint32_t lsn; - uint32_t owner_id; - uint32_t link_count; - uint32_t file_size; - - struct - { - uint32_t lsn; - uint32_t count; - } sector_map[48]; -}; - - -struct os9_direnum -{ - struct os9_fileinfo dir_info; - uint32_t index; -}; - - - -static void pick_string(const void *ptr, size_t offset, size_t length, char *dest) -{ - uint8_t b; - - while(length--) - { - b = ((uint8_t *) ptr)[offset++]; - *(dest++) = b & 0x7F; - if (b & 0x80) - length = 0; - } - *dest = '\0'; -} - - - -static void place_string(void *ptr, size_t offset, 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++) - { - b = ((uint8_t) s[i]) & 0x7F; - if (s[i+1] == '\0') - b |= 0x80; - bptr[i] = b; - } -} - - - -static os9_diskinfo *os9_get_diskinfo(imgtool::image &image) -{ - return (os9_diskinfo *) imgtool_floppy_extrabytes(image); -} - - - -static struct os9_direnum *os9_get_dirinfo(imgtool::directory &directory) -{ - return (struct os9_direnum *) directory.extra_bytes(); -} - - - -static imgtoolerr_t os9_locate_lsn(imgtool::image &image, uint32_t lsn, uint32_t *head, uint32_t *track, uint32_t *sector) -{ - const os9_diskinfo *disk_info; - - disk_info = os9_get_diskinfo(image); - if (lsn > disk_info->total_sectors) - return IMGTOOLERR_CORRUPTIMAGE; - - *track = lsn / (disk_info->sectors_per_track * disk_info->sides); - *head = (lsn / disk_info->sectors_per_track) % disk_info->sides; - *sector = (lsn % disk_info->sectors_per_track) + 1; - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t os9_read_lsn(imgtool::image &img, uint32_t lsn, int offset, void *buffer, size_t buffer_len) -{ - imgtoolerr_t err; - floperr_t ferr; - uint32_t head, track, sector; - - err = os9_locate_lsn(img, lsn, &head, &track, §or); - if (err) - return err; - - ferr = floppy_read_sector(imgtool_floppy(img), head, track, sector, offset, buffer, buffer_len); - if (ferr) - return imgtool_floppy_error(ferr); - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t os9_write_lsn(imgtool::image &img, uint32_t lsn, int offset, const void *buffer, size_t buffer_len) -{ - imgtoolerr_t err; - floperr_t ferr; - uint32_t head, track, sector; - - err = os9_locate_lsn(img, lsn, &head, &track, §or); - if (err) - return err; - - ferr = floppy_write_sector(imgtool_floppy(img), head, track, sector, offset, buffer, buffer_len, 0); /* TODO: pass ddam argument from imgtool */ - if (ferr) - return imgtool_floppy_error(ferr); - - return IMGTOOLERR_SUCCESS; -} - - - -static uint32_t os9_lookup_lsn(imgtool::image &img, - const struct os9_fileinfo *file_info, uint32_t *index) -{ - int i; - uint32_t lsn; - const os9_diskinfo *disk_info; - - disk_info = os9_get_diskinfo(img); - lsn = *index / disk_info->sector_size; - - i = 0; - while(lsn >= file_info->sector_map[i].count) - lsn -= file_info->sector_map[i++].count; - - lsn = file_info->sector_map[i].lsn + lsn; - *index %= disk_info->sector_size; - return lsn; -} - - - -static int os9_interpret_dirent(void *entry, char **filename, uint32_t *lsn, int *corrupt) -{ - int i; - char *entry_b = (char *) entry; - - *filename = NULL; - *lsn = 0; - if (corrupt) - *corrupt = false; - - if (entry_b[28] != '\0') - { - if (corrupt) - *corrupt = true; - } - - for (i = 0; (i < 28) && !(entry_b[i] & 0x80); i++) - ; - entry_b[i] &= 0x7F; - entry_b[i+1] = '\0'; - - *lsn = pick_integer_be(entry, 29, 3); - if (strcmp(entry_b, ".") && strcmp(entry_b, "..")) - *filename = entry_b; - return *filename != NULL; -} - - - -/*------------------------------------------------- - os9_decode_file_header - reads a file/directory - entry from an LSN, and decodes it --------------------------------------------------*/ - -static imgtoolerr_t os9_decode_file_header(imgtool::image &image, - int lsn, struct os9_fileinfo *info) -{ - imgtoolerr_t err; - uint32_t attributes, count; - int max_entries, i; - const os9_diskinfo *disk_info; - uint8_t header[256]; - - disk_info = os9_get_diskinfo(image); - - err = os9_read_lsn(image, lsn, 0, header, sizeof(header)); - if (err) - 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); - info->directory = (attributes & 0x80) ? 1 : 0; - info->non_sharable = (attributes & 0x40) ? 1 : 0; - info->public_execute = (attributes & 0x20) ? 1 : 0; - info->public_write = (attributes & 0x10) ? 1 : 0; - info->public_read = (attributes & 0x08) ? 1 : 0; - info->user_execute = (attributes & 0x04) ? 1 : 0; - info->user_write = (attributes & 0x02) ? 1 : 0; - info->user_read = (attributes & 0x01) ? 1 : 0; - - if (info->directory && (info->file_size % 32 != 0)) - return IMGTOOLERR_CORRUPTIMAGE; - - /* read all sector map entries */ - max_entries = (disk_info->sector_size - 16) / 5; - max_entries = (std::min)(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); - if (count <= 0) - break; - - info->sector_map[i].lsn = lsn; - info->sector_map[i].count = count; - } - info->sector_map[i].lsn = 0; - info->sector_map[i].count = 0; - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t os9_allocate_lsn(imgtool::image &image, uint32_t *lsn) -{ - uint32_t i; - os9_diskinfo *disk_info; - uint8_t b, mask; - - disk_info = os9_get_diskinfo(image); - - for (i = 0; i < disk_info->total_sectors; i++) - { - b = disk_info->allocation_bitmap[i / 8]; - mask = 1 << (7 - (i % 8)); - - if ((b & mask) == 0) - { - disk_info->allocation_bitmap[i / 8] |= mask; - *lsn = i; - return os9_write_lsn(image, 1, 0, disk_info->allocation_bitmap, disk_info->allocation_bitmap_bytes); - } - } - return IMGTOOLERR_NOSPACE; -} - - - -static imgtoolerr_t os9_deallocate_lsn(imgtool::image &image, uint32_t lsn) -{ - uint8_t mask; - os9_diskinfo *disk_info; - - disk_info = os9_get_diskinfo(image); - mask = 1 << (7 - (lsn % 8)); - disk_info->allocation_bitmap[lsn / 8] &= ~mask; - return os9_write_lsn(image, 1, 0, disk_info->allocation_bitmap, disk_info->allocation_bitmap_bytes); -} - - - -static uint32_t os9_get_free_lsns(imgtool::image &image) -{ - const os9_diskinfo *disk_info; - uint32_t i, free_lsns; - uint8_t b; - - disk_info = os9_get_diskinfo(image); - free_lsns = 0; - - for (i = 0; i < disk_info->total_sectors; i++) - { - b = disk_info->allocation_bitmap[i / 8]; - b >>= (7 - (i % 8)); - free_lsns += ~b & 1; - } - - return free_lsns; -} - - - -static imgtoolerr_t os9_corrupt_file_error(const struct os9_fileinfo *file_info) -{ - imgtoolerr_t err; - if (file_info->directory) - err = IMGTOOLERR_CORRUPTDIR; - else - err = IMGTOOLERR_CORRUPTFILE; - return err; -} - - - -static imgtoolerr_t os9_set_file_size(imgtool::image &image, - struct os9_fileinfo *file_info, uint32_t new_size) -{ - imgtoolerr_t err; - const os9_diskinfo *disk_info; - uint32_t new_lsn_count, current_lsn_count; - uint32_t free_lsns, lsn, i; - int sector_map_length = -1; - uint8_t header[256]; - - /* easy way out? */ - if (file_info->file_size == new_size) - return IMGTOOLERR_SUCCESS; - - disk_info = os9_get_diskinfo(image); - - free_lsns = os9_get_free_lsns(image); - current_lsn_count = (file_info->file_size + disk_info->sector_size - 1) / disk_info->sector_size; - new_lsn_count = (new_size + disk_info->sector_size - 1) / disk_info->sector_size; - - /* check to see if the file is growing and we do not have enough space */ - if ((new_lsn_count > current_lsn_count) && (new_lsn_count - current_lsn_count > free_lsns)) - return IMGTOOLERR_NOSPACE; - - if (current_lsn_count != new_lsn_count) - { - /* first find out the size of our sector map */ - sector_map_length = 0; - lsn = 0; - 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); - - lsn += file_info->sector_map[sector_map_length].count; - sector_map_length++; - } - - /* keep in mind that the sector_map might not parallel our expected - * current LSN count; we should tolerate this abnormality */ - current_lsn_count = lsn; - - while(current_lsn_count > new_lsn_count) - { - /* shrink this file */ - lsn = file_info->sector_map[sector_map_length - 1].lsn + - file_info->sector_map[sector_map_length - 1].count - 1; - - err = os9_deallocate_lsn(image, lsn); - if (err) - return err; - - file_info->sector_map[sector_map_length - 1].count--; - while(sector_map_length > 0 && (file_info->sector_map[sector_map_length - 1].count == 0)) - sector_map_length--; - current_lsn_count--; - } - - while(current_lsn_count < new_lsn_count) - { - /* grow this file */ - err = os9_allocate_lsn(image, &lsn); - if (err) - return err; - - if ((sector_map_length > 0) && ((file_info->sector_map[sector_map_length - 1].lsn + - file_info->sector_map[sector_map_length - 1].count) == lsn)) - { - file_info->sector_map[sector_map_length - 1].count++; - } - else if (sector_map_length >= std::size(file_info->sector_map)) - { - return IMGTOOLERR_NOSPACE; - } - else - { - file_info->sector_map[sector_map_length].lsn = lsn; - file_info->sector_map[sector_map_length].count = 1; - sector_map_length++; - file_info->sector_map[sector_map_length].lsn = 0; - file_info->sector_map[sector_map_length].count = 0; - } - current_lsn_count++; - } - } - - /* now lets write back the sector */ - err = os9_read_lsn(image, file_info->lsn, 0, header, sizeof(header)); - if (err) - return err; - - file_info->file_size = new_size; - place_integer_be(header, 9, 4, file_info->file_size); - - /* do we have to write the sector map? */ - if (sector_map_length >= 0) - { - for (i = 0; i < (std::min)(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); - } - } - - err = os9_write_lsn(image, file_info->lsn, 0, header, disk_info->sector_size); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - - -/*------------------------------------------------- - os9_lookup_path - walks an OS-9 directory - structure to find a file, or optionally, create - a file --------------------------------------------------*/ - -static imgtoolerr_t os9_lookup_path(imgtool::image &img, const char *path, - creation_policy_t create, struct os9_fileinfo *file_info, - uint32_t *parent_lsn, uint32_t *dirent_lsn, uint32_t *dirent_index) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - struct os9_fileinfo dir_info; - uint32_t index, current_lsn, dir_size; - uint32_t entry_index = 0; - uint32_t free_entry_index = 0xffffffff; - uint32_t entry_lsn = 0; - uint32_t allocated_lsn = 0; - uint8_t entry[32]; - uint8_t block[64]; - char *filename; - const os9_diskinfo *disk_info; - - disk_info = os9_get_diskinfo(img); - current_lsn = disk_info->root_dir_lsn; - - if (parent_lsn) - *parent_lsn = 0; - - /* we have to transverse each path element */ - while(*path) - { - if (parent_lsn) - *parent_lsn = current_lsn; - - /* decode the directory header of this directory */ - err = os9_decode_file_header(img, current_lsn, &dir_info); - if (err) - goto done; - dir_size = dir_info.file_size; - - /* sanity check directory */ - if (!dir_info.directory) - { - err = (current_lsn == disk_info->root_dir_lsn) ? IMGTOOLERR_CORRUPTIMAGE : IMGTOOLERR_INVALIDPATH; - goto done; - } - - /* walk the directory */ - for (index = 0; index < dir_size; index += 32) - { - entry_index = index; - entry_lsn = os9_lookup_lsn(img, &dir_info, &entry_index); - - err = os9_read_lsn(img, entry_lsn, entry_index, entry, sizeof(entry)); - if (err) - goto done; - - /* remember first free entry found */ - if( free_entry_index == 0xffffffff ) - { - if( entry[0] == 0 ) - free_entry_index = index; - } - - if (os9_interpret_dirent(entry, &filename, ¤t_lsn, NULL)) - { - if (!strcmp(path, filename)) - break; - } - - } - - /* at the end of the file? */ - if (index >= dir_size) - { - /* if we're not creating, or we are creating but we have not fully - * transversed the directory, error out */ - if (!create || path[strlen(path) + 1]) - { - err = IMGTOOLERR_PATHNOTFOUND; - goto done; - } - - /* allocate a new LSN */ - err = os9_allocate_lsn(img, &allocated_lsn); - if (err) - goto done; - - /* write the file */ - memset(block, 0, sizeof(block)); - place_integer_be(block, 0, 1, 0x1B | ((create == CREATE_DIR) ? 0x80 : 0x00)); - err = os9_write_lsn(img, allocated_lsn, 0, block, sizeof(block)); - if (err) - goto done; - - if( free_entry_index == 0xffffffff ) - { - /* expand the directory to hold the new entry */ - err = os9_set_file_size(img, &dir_info, dir_size + 32); - if (err) - goto done; - } - else - /* use first unused entry in directory */ - dir_size = free_entry_index; - - /* now prepare the directory entry */ - memset(entry, 0, sizeof(entry)); - place_string(entry, 0, 28, path); - place_integer_be(entry, 29, 3, allocated_lsn); - - /* now write the directory entry */ - entry_index = dir_size; - entry_lsn = os9_lookup_lsn(img, &dir_info, &entry_index); - err = os9_write_lsn(img, entry_lsn, entry_index, entry, 32); - if (err) - goto done; - - /* directory entry append complete; no need to hold this lsn */ - current_lsn = allocated_lsn; - allocated_lsn = 0; - } - path += strlen(path) + 1; - } - - if (file_info) - { - err = os9_decode_file_header(img, current_lsn, file_info); - if (err) - goto done; - } - - if (dirent_lsn) - *dirent_lsn = entry_lsn; - if (dirent_index) - *dirent_index = entry_index; - -done: - if (allocated_lsn != 0) - os9_deallocate_lsn(img, allocated_lsn); - return err; -} - - - -static imgtoolerr_t os9_diskimage_open(imgtool::image &image, imgtool::stream::ptr &&dummy) -{ - imgtoolerr_t err; - floperr_t ferr; - os9_diskinfo *info; - uint32_t track_size_in_sectors, i; //, attributes; - uint8_t header[256]; - uint32_t allocation_bitmap_lsns; - uint8_t b, mask; - - info = os9_get_diskinfo(image); - - ferr = floppy_read_sector(imgtool_floppy(image), 0, 0, 1, 0, header, sizeof(header)); - 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->sides = (info->format_flags & 0x01) ? 2 : 1; - info->double_density = (info->format_flags & 0x02) ? 1 : 0; - info->double_track = (info->format_flags & 0x04) ? 1 : 0; - info->quad_track_density = (info->format_flags & 0x08) ? 1 : 0; - info->octal_track_density = (info->format_flags & 0x10) ? 1 : 0; - - pick_string(header, 31, 32, info->name); - - if (info->sector_size == 0) - info->sector_size = 256; - - /* does the root directory and allocation bitmap collide? */ - allocation_bitmap_lsns = (info->allocation_bitmap_bytes + info->sector_size - 1) / info->sector_size; - if (1 + allocation_bitmap_lsns > info->root_dir_lsn) - return IMGTOOLERR_CORRUPTIMAGE; - - /* is the allocation bitmap too big? */ - 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) - return IMGTOOLERR_CORRUPTIMAGE; - - /* zero sectors per track? */ - if (info->sectors_per_track == 0) - return IMGTOOLERR_CORRUPTIMAGE; - - /* do we have an odd number of sectors? */ - if (info->total_sectors % info->sectors_per_track) - return IMGTOOLERR_CORRUPTIMAGE; - - /* read the allocation bitmap */ - for (i = 0; i < allocation_bitmap_lsns; i++) - { - err = os9_read_lsn(image, 1 + i, 0, &info->allocation_bitmap[i * info->sector_size], - std::min(info->allocation_bitmap_bytes - (i * info->sector_size), info->sector_size)); - if (err) - return err; - } - - /* check to make sure that the allocation bitmap and root sector are reserved */ - for (i = 0; i <= allocation_bitmap_lsns; i++) - { - b = info->allocation_bitmap[i / 8]; - mask = 1 << (7 - (i % 8)); - if ((b & mask) == 0) - return IMGTOOLERR_CORRUPTIMAGE; - } - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t os9_diskimage_create(imgtool::image &img, imgtool::stream::ptr &&stream, util::option_resolution *opts) -{ - imgtoolerr_t err; - std::vector header; - uint32_t heads, tracks, sectors, sector_bytes, first_sector_id; - uint32_t cluster_size, owner_id; - uint32_t allocation_bitmap_bits, allocation_bitmap_lsns; - uint32_t attributes, format_flags, disk_id; - uint32_t i; - int32_t total_allocated_sectors; - const char *title; - time_t t; - struct tm *ltime; - - time(&t); - ltime = localtime(&t); - - heads = opts->lookup_int('H'); - tracks = opts->lookup_int('T'); - sectors = opts->lookup_int('S'); - sector_bytes = opts->lookup_int('L'); - first_sector_id = opts->lookup_int('F'); - title = ""; - - header.resize(sector_bytes); - - if (sector_bytes > 256) - sector_bytes = 256; - cluster_size = 1; - owner_id = 1; - disk_id = 1; - attributes = 0; - allocation_bitmap_bits = heads * tracks * sectors / cluster_size; - allocation_bitmap_lsns = (allocation_bitmap_bits / 8 + sector_bytes - 1) / sector_bytes; - 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); - - /* 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 */ - - 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) - goto done; - - total_allocated_sectors = 1 + allocation_bitmap_lsns + 1 + 7; - - for (i = 0; i < allocation_bitmap_lsns; i++) - { - memset(&header[0], 0x00, sector_bytes); - - if (total_allocated_sectors > (8 * 256)) - { - memset(&header[0], 0xff, sector_bytes); - total_allocated_sectors -= (8 * 256); - } - else if (total_allocated_sectors > 1 ) - { - int offset; - uint8_t mask; - - while( total_allocated_sectors >= 0 ) - { - offset = total_allocated_sectors / 8; - mask = 1 << (7 - ( total_allocated_sectors % 8 ) ); - - header[offset] |= mask; - total_allocated_sectors--; - } - } - - err = (imgtoolerr_t)floppy_write_sector(imgtool_floppy(img), 0, 0, first_sector_id + 1 + i, 0, &header[0], sector_bytes, 0); /* TODO: pass ddam argument from imgtool */ - if (err) - goto done; - } - - memset(&header[0], 0, sector_bytes); - header[0x00] = 0xBF; - header[0x01] = 0x00; - header[0x02] = 0x00; - header[0x03] = (uint8_t) ltime->tm_year; - header[0x04] = (uint8_t) ltime->tm_mon + 1; - header[0x05] = (uint8_t) ltime->tm_mday; - header[0x06] = (uint8_t) ltime->tm_hour; - header[0x07] = (uint8_t) ltime->tm_min; - header[0x08] = 0x02; - header[0x09] = 0x00; - header[0x0A] = 0x00; - header[0x0B] = 0x00; - header[0x0C] = 0x40; - 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); - - 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) - goto done; - - memset(&header[0], 0, sector_bytes); - header[0x00] = 0x2E; - header[0x01] = 0xAE; - header[0x1F] = 1 + allocation_bitmap_lsns; - header[0x20] = 0xAE; - header[0x3F] = 1 + allocation_bitmap_lsns; - err = (imgtoolerr_t)floppy_write_sector(imgtool_floppy(img), 0, 0, first_sector_id + 2 + allocation_bitmap_lsns, 0, &header[0], sector_bytes, 0); /* TOOD: pass ddam argument from imgtool */ - if (err) - goto done; - -done: - return err; -} - - - -static imgtoolerr_t os9_diskimage_beginenum(imgtool::directory &enumeration, const char *path) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - struct os9_direnum *os9enum; - imgtool::image &image(enumeration.image()); - - os9enum = os9_get_dirinfo(enumeration); - - err = os9_lookup_path(image, path, CREATE_NONE, &os9enum->dir_info, NULL, NULL, NULL); - if (err) - goto done; - - /* this had better be a directory */ - if (!os9enum->dir_info.directory) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto done; - } - -done: - return err; -} - - - -static imgtoolerr_t os9_diskimage_nextenum(imgtool::directory &enumeration, imgtool_dirent &ent) -{ - struct os9_direnum *os9enum; - uint32_t lsn, index; - imgtoolerr_t err; - uint8_t dir_entry[32]; - char filename[29]; - struct os9_fileinfo file_info; - imgtool::image &image(enumeration.image()); - - os9enum = os9_get_dirinfo(enumeration); - - do - { - /* check for EOF */ - if (os9enum->index >= os9enum->dir_info.file_size) - { - ent.eof = 1; - return IMGTOOLERR_SUCCESS; - } - - /* locate the LSN and offset for this directory entry */ - index = os9enum->index; - lsn = os9_lookup_lsn(image, &os9enum->dir_info, &index); - - /* read the directory entry out of the lSN */ - err = os9_read_lsn(image, lsn, index, dir_entry, sizeof(dir_entry)); - if (err) - return err; - - if (dir_entry[0]) - { - /* read the file or directory name */ - pick_string(dir_entry, 0, 28, filename); - - /* we have certain expectations of the directory contents; the - * first directory entry should be "..", the second ".", and - * subsequent entries should never be "." or ".." */ - switch(os9enum->index) - { - case 0: - if (strcmp(filename, "..")) - imgtool_warn("First entry in directory should be \"..\" and not \"%s\"", filename); - break; - - case 32: - if (strcmp(filename, ".")) - imgtool_warn("Second entry in directory should be \".\" and not \"%s\"", filename); - break; - - default: - if (!strcmp(filename, ".") || !strcmp(filename, "..")) - imgtool_warn("Directory entry %d should not be \"%s\"", index / 32, filename); - break; - } - - /* 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)) - { - imgtool_warn("Directory \".\" does not point back to same directory"); - } - } - else - { - /* no more directory entries */ - filename[0] = '\0'; - } - - /* move on to the next directory entry */ - os9enum->index += 32; - } - while(!filename[0] || !strcmp(filename, ".") || !strcmp(filename, "..")); - - /* read file attributes */ - lsn = pick_integer_be(dir_entry, 29, 3); - err = os9_decode_file_header(enumeration.image(), lsn, &file_info); - if (err) - return err; - - /* fill out imgtool_dirent structure */ - 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' : '-', - file_info.public_write ? 'w' : '-', - file_info.public_read ? 'r' : '-', - file_info.user_execute ? 'x' : '-', - file_info.user_write ? 'w' : '-', - file_info.user_read ? 'r' : '-'); - - ent.directory = file_info.directory; - ent.corrupt = (dir_entry[28] != 0); - ent.filesize = file_info.file_size; - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t os9_diskimage_freespace(imgtool::partition &partition, uint64_t *size) -{ - imgtool::image &image(partition.image()); - const os9_diskinfo *disk_info; - uint32_t free_lsns; - - disk_info = os9_get_diskinfo(image); - free_lsns = os9_get_free_lsns(image); - - *size = free_lsns * disk_info->sector_size; - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t os9_diskimage_readfile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &destf) -{ - imgtoolerr_t err; - imgtool::image &img(partition.image()); - const os9_diskinfo *disk_info; - struct os9_fileinfo file_info; - uint8_t buffer[256]; - int i, j; - uint32_t file_size; - uint32_t used_size; - - disk_info = os9_get_diskinfo(img); - - err = os9_lookup_path(img, filename, CREATE_NONE, &file_info, NULL, NULL, NULL); - if (err) - return err; - if (file_info.directory) - return IMGTOOLERR_FILENOTFOUND; - file_size = file_info.file_size; - - for (i = 0; file_info.sector_map[i].count > 0; i++) - { - for (j = 0; j < file_info.sector_map[i].count; j++) - { - used_size = std::min(file_size, disk_info->sector_size); - err = os9_read_lsn(img, file_info.sector_map[i].lsn + j, 0, - buffer, used_size); - if (err) - return err; - destf.write(buffer, used_size); - file_size -= used_size; - } - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t os9_diskimage_writefile(imgtool::partition &partition, const char *path, const char *fork, imgtool::stream &sourcef, util::option_resolution *opts) -{ - imgtoolerr_t err; - imgtool::image &image(partition.image()); - struct os9_fileinfo file_info; - size_t write_size; - std::vector buf; - int i = -1; - uint32_t lsn = 0; - uint32_t count = 0; - uint32_t sz; - const os9_diskinfo *disk_info; - - disk_info = os9_get_diskinfo(image); - - buf.resize(disk_info->sector_size); - - err = os9_lookup_path(image, path, CREATE_FILE, &file_info, NULL, NULL, NULL); - if (err) - goto done; - - sz = (uint32_t) sourcef.size(); - - err = os9_set_file_size(image, &file_info, sz); - if (err) - goto done; - - while(sz > 0) - { - write_size = (std::min)(sz, disk_info->sector_size); - - sourcef.read(&buf[0], write_size); - - while(count == 0) - { - i++; - lsn = file_info.sector_map[i].lsn; - count = file_info.sector_map[i].count; - } - - err = os9_write_lsn(image, lsn, 0, &buf[0], write_size); - if (err) - goto done; - - lsn++; - count--; - sz -= write_size; - } - -done: - return err; -} - - - -static imgtoolerr_t os9_diskimage_delete(imgtool::partition &partition, const char *path, - unsigned int delete_directory) -{ - imgtoolerr_t err; - imgtool::image &image(partition.image()); - struct os9_fileinfo file_info; - uint32_t dirent_lsn, dirent_index; - uint32_t entry_lsn, entry_index; - uint32_t i, j, lsn; - uint8_t b; - - //disk_info = os9_get_diskinfo(image); - - err = os9_lookup_path(image, path, CREATE_NONE, &file_info, NULL, &dirent_lsn, &dirent_index); - if (err) - return err; - if (file_info.directory != delete_directory) - return IMGTOOLERR_FILENOTFOUND; - - /* make sure that if we are deleting a directory, it is empty */ - if (delete_directory) - { - for (i = 64; i < file_info.file_size; i += 32) - { - entry_index = i; - entry_lsn = os9_lookup_lsn(image, &file_info, &entry_index); - - err = os9_read_lsn(image, entry_lsn, entry_index, &b, 1); - if (err) - return err; - - /* this had better be a deleted file, if not we can't delete */ - if (b != 0) - return IMGTOOLERR_DIRNOTEMPTY; - } - } - - /* zero out the file entry */ - b = '\0'; - err = os9_write_lsn(image, dirent_lsn, dirent_index, &b, 1); - if (err) - return err; - - /* get the link count */ - err = os9_read_lsn(image, file_info.lsn, 8, &b, 1); - if (err) - return err; - - if (b > 0) - b--; - if (b > 0) - { - /* link count is greater than zero */ - err = os9_write_lsn(image, file_info.lsn, 8, &b, 1); - if (err) - return err; - } - else - { - /* no more links; outright delete the file */ - err = os9_deallocate_lsn(image, file_info.lsn); - if (err) - return err; - - 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++) - { - err = os9_deallocate_lsn(image, lsn + j); - if (err) - return err; - } - } - } - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t os9_diskimage_deletefile(imgtool::partition &partition, const char *path) -{ - return os9_diskimage_delete(partition, path, 0); -} - - - -static imgtoolerr_t os9_diskimage_createdir(imgtool::partition &partition, const char *path) -{ - imgtoolerr_t err; - imgtool::image &image(partition.image()); - struct os9_fileinfo file_info; - uint8_t dir_data[64]; - uint32_t parent_lsn; - - err = os9_lookup_path(image, path, CREATE_DIR, &file_info, &parent_lsn, NULL, NULL); - if (err) - goto done; - - err = os9_set_file_size(image, &file_info, 64); - if (err) - goto done; - - /* 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); - - err = os9_write_lsn(image, file_info.sector_map[0].lsn, 0, dir_data, sizeof(dir_data)); - if (err) - goto done; - -done: - return err; -} - - - -static imgtoolerr_t os9_diskimage_deletedir(imgtool::partition &partition, const char *path) -{ - return os9_diskimage_delete(partition, path, 1); -} - - - -void os9_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_IMAGE_EXTRA_BYTES: info->i = sizeof(os9_diskinfo); break; - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(struct os9_direnum); break; - case IMGTOOLINFO_INT_PATH_SEPARATOR: info->i = '/'; break; - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "os9"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "OS-9 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_FLOPPY_CREATE: info->create = os9_diskimage_create; break; - case IMGTOOLINFO_PTR_FLOPPY_OPEN: info->open = os9_diskimage_open; break; - case IMGTOOLINFO_PTR_BEGIN_ENUM: info->begin_enum = os9_diskimage_beginenum; break; - case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = os9_diskimage_nextenum; break; - case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = os9_diskimage_freespace; break; - case IMGTOOLINFO_PTR_READ_FILE: info->read_file = os9_diskimage_readfile; break; - case IMGTOOLINFO_PTR_WRITE_FILE: info->write_file = os9_diskimage_writefile; break; - case IMGTOOLINFO_PTR_DELETE_FILE: info->delete_file = os9_diskimage_deletefile; break; - case IMGTOOLINFO_PTR_CREATE_DIR: info->create_dir = os9_diskimage_createdir; break; - case IMGTOOLINFO_PTR_DELETE_DIR: info->delete_dir = os9_diskimage_deletedir; break; - case IMGTOOLINFO_PTR_FLOPPY_FORMAT: info->p = (void *) floppyoptions_coco; break; - } -} diff --git a/src/tools/imgtool/modules/pc_flop.cpp b/src/tools/imgtool/modules/pc_flop.cpp deleted file mode 100644 index fd08b8e..0000000 --- a/src/tools/imgtool/modules/pc_flop.cpp +++ /dev/null @@ -1,176 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Raphael Nabet -/**************************************************************************** - - pc_flop.c - - PC floppies - -****************************************************************************/ - -#include "imgtool.h" -#include "fat.h" -#include "iflopimg.h" - -#include "formats/imageutl.h" -#include "formats/pc_dsk_legacy.h" - -#include "opresolv.h" - -#define FAT_SECLEN 512 - - -static imgtoolerr_t fat_image_create(imgtool::image &image, imgtool::stream::ptr &&stream, util::option_resolution *opts) -{ - imgtoolerr_t err; - uint32_t tracks, heads, sectors; - uint8_t buffer[FAT_SECLEN]; - imgtool_class imgclass = { fat_get_info }; - imgtoolerr_t (*fat_partition_create)(imgtool::image &image, uint64_t first_block, uint64_t block_count); - - tracks = opts->lookup_int('T'); - heads = opts->lookup_int('H'); - sectors = opts->lookup_int('S'); - - /* 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)); - err = image.write_block(0, buffer); - if (err) - goto done; - - /* load fat_partition_create */ - fat_partition_create = (imgtoolerr_t (*)(imgtool::image &, uint64_t, uint64_t)) - imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_CREATE_PARTITION); - - /* actually create the partition */ - err = fat_partition_create(image, 0, ((uint64_t) tracks) * heads * sectors); - if (err) - goto done; - -done: - return err; -} - - - -static imgtoolerr_t fat_image_get_geometry(imgtool::image &image, uint32_t *tracks, uint32_t *heads, uint32_t *sectors) -{ - imgtoolerr_t err; - uint64_t total_sectors; - uint8_t buffer[FAT_SECLEN]; - - err = image.read_block(0, buffer); - if (err) - return err; - - total_sectors = pick_integer_le(buffer, 19, 2) - | (pick_integer_le(buffer, 32, 4) << 16); - - *sectors = pick_integer_le(buffer, 24, 2); - *heads = pick_integer_le(buffer, 26, 2); - *tracks = total_sectors / *heads / *sectors; - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_get_sector_position(imgtool::image &image, uint32_t sector_index, - uint32_t *track, uint32_t *head, uint32_t *sector) -{ - imgtoolerr_t err; - uint32_t tracks, heads, sectors; - - if (sector_index == 0) - { - /* special case */ - *head = 0; - *track = 0; - *sector = 1; - } - else - { - err = image.get_geometry(&tracks, &heads, §ors); - if (err) - return err; - - *track = sector_index / sectors / heads; - *head = (sector_index / sectors) % heads; - *sector = 1 + (sector_index % sectors); - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_image_readblock(imgtool::image &image, void *buffer, uint64_t block) -{ - imgtoolerr_t err; - floperr_t ferr; - uint32_t track, head, sector; - uint32_t block_size; - - err = image.get_block_size(block_size); - if (err) - return err; - - err = fat_get_sector_position(image, block, &track, &head, §or); - if (err) - return err; - - ferr = floppy_read_sector(imgtool_floppy(image), head, track, sector, 0, buffer, block_size); - if (ferr) - return imgtool_floppy_error(ferr); - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_image_writeblock(imgtool::image &image, const void *buffer, uint64_t block) -{ - imgtoolerr_t err; - floperr_t ferr; - uint32_t track, head, sector; - uint32_t block_size; - - err = image.get_block_size(block_size); - if (err) - return err; - - err = fat_get_sector_position(image, block, &track, &head, §or); - if (err) - return err; - - ferr = floppy_write_sector(imgtool_floppy(image), head, track, sector, 0, buffer, block_size, 0); /* TODO: pass ddam argument from imgtool */ - if (ferr) - return imgtool_floppy_error(ferr); - return IMGTOOLERR_SUCCESS; -} - - - -void pc_floppy_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_BLOCK_SIZE: info->i = FAT_SECLEN; break; - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "fat"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "FAT format"); 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 = fat_image_create; break; - case IMGTOOLINFO_PTR_FLOPPY_FORMAT: info->p = (void *) floppyoptions_pc; break; - case IMGTOOLINFO_PTR_READ_BLOCK: info->read_block = fat_image_readblock; break; - case IMGTOOLINFO_PTR_WRITE_BLOCK: info->write_block = fat_image_writeblock; break; - case IMGTOOLINFO_PTR_GET_GEOMETRY: info->get_geometry = fat_image_get_geometry; break; - - default: fat_get_info(imgclass, state, info); break; - } -} diff --git a/src/tools/imgtool/modules/pc_hard.cpp b/src/tools/imgtool/modules/pc_hard.cpp deleted file mode 100644 index c65db87..0000000 --- a/src/tools/imgtool/modules/pc_hard.cpp +++ /dev/null @@ -1,470 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Raphael Nabet -/**************************************************************************** - - pc_hard.c - - PC hard drives - -***************************************************************************** - - Master boot record format: - - Offset Length Description - ------ ------ ----------- - 0 446 Boot machine code - 446 16 Partion #1 info - 462 16 Partion #2 info - 478 16 Partion #3 info - 494 16 Partion #4 info - 510 2 Magic bytes (0x55 0xAA) - - - Partition info format: - - Offset Length Description - ------ ------ ----------- - 0 1 Bootable (0x80=bootable 0x00=not bootable) - 1 1 Starting head - 2 1 Starting sector (bits 5-0) and high bits of starting track (bits 6-5) - 3 1 Low bits of starting track - 4 1 Partition type: - 0x00 Unused - 0x?1 FAT12 (0-15 MB) - 0x?2 XENIX - 0x?4 FAT16 (16-32 MB) - 0x?6 FAT16` (32 MB-2 GB) - 0x?7 HPFS or NTFS - 0x?A Boot Manager - 0x?B FAT32 (512 MB-2 TB) - 0x?C FAT32 (512 MB-2 TB LBA) - 0x1? OS/2 Boot manager/Win95 hidden - 0xC? DR-DOS secured partition - 0xD? Multiuser DOS secured partition - 0xE? SpeedStor extended partition - 5 1 Ending head - 6 1 Ending sector (bits 5-0) and high bits of ending track (bits 6-5) - 7 1 Low bits of ending track - 8 4 Sector index of beginning of partition - 12 4 Total sectors in partition - -****************************************************************************/ -#include "imgtool.h" -#include "formats/imageutl.h" -#include "imghd.h" - -#include "opresolv.h" - -#define FAT_SECLEN 512 - -OPTION_GUIDE_START( pc_chd_create_optionguide ) - OPTION_INT('T', "cylinders", "Cylinders" ) - OPTION_INT('H', "heads", "Heads" ) - OPTION_INT('S', "sectors", "Sectors" ) -OPTION_GUIDE_END - -static const char pc_chd_create_optionspec[] = "H1-[16];S1-[32]-63;T10/20/30/40/50/60/70/80/90/[100]/110/120/130/140/150/160/170/180/190/200"; - -static const char fat8_string[8] = { 'F', 'A', 'T', ' ', ' ', ' ', ' ', ' ' }; -static const char fat12_string[8] = { 'F', 'A', 'T', '1', '2', ' ', ' ', ' ' }; -static const char fat16_string[8] = { 'F', 'A', 'T', '1', '6', ' ', ' ', ' ' }; -//static const char fat32_string[8] = { 'F', 'A', 'T', '3', '2', ' ', ' ', ' ' }; - -/* imports from fat.c */ -extern void fat_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info); - - -struct pc_chd_image_info -{ - struct mess_hard_disk_file hard_disk; - - struct - { - unsigned int corrupt : 1; - uint8_t partition_type; - uint32_t fat_bits; - uint32_t starting_track; - uint32_t starting_head; - uint32_t starting_sector; - uint32_t ending_track; - uint32_t ending_head; - uint32_t ending_sector; - uint32_t sector_index; - uint32_t total_sectors; - } partitions[4]; -}; - - - -static pc_chd_image_info *pc_chd_get_image_info(imgtool::image &image) -{ - return (pc_chd_image_info *) image.extra_bytes(); -} - - - -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); - - *sector = block % hd_info->sectors; - *head = (block / hd_info->sectors) % hd_info->heads; - *cylinder = block / hd_info->sectors / hd_info->heads; -} - - - -static imgtoolerr_t pc_chd_partition_create(imgtool::image &image, int partition_index, uint64_t first_block, uint64_t block_count) -{ - imgtoolerr_t err; - uint8_t header_block[FAT_SECLEN]; - uint8_t partition_block[FAT_SECLEN]; - uint8_t partition_type; - uint8_t *fat_type; - uint8_t *partition_entry; - uint32_t first_cylinder, first_head, first_sector; - uint32_t last_cylinder, last_head, last_sector; - imgtool_class imgclass = { fat_get_info }; - imgtoolerr_t (*fat_partition_create)(imgtool::image &image, uint64_t first_block, uint64_t block_count); - - /* sanity checks */ - assert((partition_index >= 0) && (partition_index <= 3)); - - /* compute geometry */ - pc_chd_locate_block(image, first_block, &first_cylinder, &first_head, &first_sector); - pc_chd_locate_block(image, first_block + block_count - 1, &last_cylinder, &last_head, &last_sector); - - /* load fat_partition_create */ - fat_partition_create = (imgtoolerr_t (*)(imgtool::image &, uint64_t, uint64_t)) - imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_CREATE_PARTITION); - - /* first create the actual partition */ - err = fat_partition_create(image, first_block, block_count); - if (err) - goto done; - - /* read the first block of the partition, to determine the type of FAT */ - err = image.read_block(first_block, partition_block); - if (err) - goto done; - fat_type = &partition_block[54]; - if (!memcmp(fat_type, fat8_string, sizeof(fat8_string))) - partition_type = 0x01; - else if (!memcmp(fat_type, fat12_string, sizeof(fat12_string))) - partition_type = 0x01; - else if ((!memcmp(fat_type, fat16_string, sizeof(fat16_string))) && (block_count < 32*1024*1024/FAT_SECLEN)) - partition_type = 0x04; - else if ((!memcmp(fat_type, fat16_string, sizeof(fat16_string))) && (block_count >= 32*1024*1024/FAT_SECLEN)) - partition_type = 0x06; - else - partition_type = 0x0B; - - /* read the partition header */ - err = image.read_block(0, header_block); - if (err) - goto done; - - /* 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); - - /* write the partition header */ - err = image.write_block(0, header_block); - if (err) - goto done; - -done: - return err; -} - - - -static imgtoolerr_t pc_chd_read_partition_header(imgtool::image &image) -{ - imgtoolerr_t err; - const uint8_t *partition_info; - pc_chd_image_info *info; - uint8_t buffer[FAT_SECLEN]; - - info = pc_chd_get_image_info(image); - - /* read the initial block */ - err = image.read_block(0, buffer); - if (err) - return err; - - /* magic bytes present? */ - if ((buffer[510] != 0x55) || (buffer[511] != 0xAA)) - return IMGTOOLERR_CORRUPTIMAGE; - - for (int i = 0; i < std::size(info->partitions); i++) - { - partition_info = &buffer[446 + i * 16]; - - info->partitions[i].partition_type = partition_info[4]; - info->partitions[i].starting_head = partition_info[1]; - info->partitions[i].starting_track = ((partition_info[2] << 2) & 0xFF00) | partition_info[3]; - info->partitions[i].starting_sector = partition_info[2] & 0x3F; - info->partitions[i].ending_head = partition_info[5]; - 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); - - if (info->partitions[i].starting_track > info->partitions[i].ending_track) - return IMGTOOLERR_CORRUPTIMAGE; - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t pc_chd_image_create(imgtool::image &image, imgtool::stream::ptr &&stream, util::option_resolution *opts) -{ - imgtoolerr_t err; - uint32_t cylinders, heads, sectors; - pc_chd_image_info *info; - uint8_t header_block[FAT_SECLEN]; - - cylinders = opts->lookup_int('T'); - heads = opts->lookup_int('H'); - sectors = opts->lookup_int('S'); - - info = pc_chd_get_image_info(image); - - /* create the hard disk image */ - err = imghd_create(*stream, 0, cylinders, heads, sectors, FAT_SECLEN); - if (err) - goto done; - - err = imghd_open(*stream, &info->hard_disk); - if (err) - goto done; - - /* set up partition header block */ - memset(header_block, 0, sizeof(header_block)); - header_block[510] = 0x55; - header_block[511] = 0xAA; - err = image.write_block(0, header_block); - if (err) - goto done; - - err = pc_chd_partition_create(image, 0, 1, cylinders * heads * sectors - 1); - if (err) - goto done; - - err = pc_chd_read_partition_header(image); - if (err) - goto done; - -done: - if (err) - imghd_close(&info->hard_disk); - return err; -} - - - -static imgtoolerr_t pc_chd_image_open(imgtool::image &image, imgtool::stream::ptr &&stream) -{ - imgtoolerr_t err; - pc_chd_image_info *info; - - info = pc_chd_get_image_info(image); - - /* open the hard drive */ - err = imghd_open(*stream, &info->hard_disk); - if (err) - return err; - - err = pc_chd_read_partition_header(image); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - - -static void pc_chd_image_close(imgtool::image &image) -{ - pc_chd_image_info *info; - info = pc_chd_get_image_info(image); - imghd_close(&info->hard_disk); -} - - - -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); - - *tracks = hd_info->cylinders; - *heads = hd_info->heads; - *sectors = hd_info->sectors; - return IMGTOOLERR_SUCCESS; -} - - - -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); - lbasector = track; - lbasector *= hd_info->heads; - lbasector += head; - lbasector *= hd_info->sectors; - lbasector += sector; - return lbasector; -} - - - -static imgtoolerr_t pc_chd_image_readsector(imgtool::image &image, uint32_t track, uint32_t head, uint32_t sector, std::vector &buffer) -{ - 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; - try { buffer.resize(sector_size); } - catch (std::bad_alloc const &) { return IMGTOOLERR_OUTOFMEMORY; } - - // read the data - return imghd_read(&info->hard_disk, - pc_chd_calc_lbasector(*info, track, head, sector), - &buffer[0]); -} - - - -static imgtoolerr_t pc_chd_image_writesector(imgtool::image &image, uint32_t track, uint32_t head, uint32_t sector, const void *buffer, size_t len, int ddam) -{ - pc_chd_image_info *info; - info = pc_chd_get_image_info(image); - return imghd_write(&info->hard_disk, - pc_chd_calc_lbasector(*info, track, head, sector), - buffer); -} - - - -static imgtoolerr_t pc_chd_image_readblock(imgtool::image &image, void *buffer, uint64_t block) -{ - pc_chd_image_info *info; - info = pc_chd_get_image_info(image); - return imghd_read(&info->hard_disk, block, buffer); -} - - - -static imgtoolerr_t pc_chd_image_writeblock(imgtool::image &image, const void *buffer, uint64_t block) -{ - pc_chd_image_info *info; - info = pc_chd_get_image_info(image); - return imghd_write(&info->hard_disk, block, buffer); -} - - - -static imgtoolerr_t pc_chd_list_partitions(imgtool::image &image, std::vector &partitions) -{ - pc_chd_image_info *info; - size_t i; - - info = pc_chd_get_image_info(image); - - for (i = 0; i < 4; i++) - { - // what type of partition is this? - imgtool_get_info partition_get_info; - switch(info->partitions[i].partition_type) - { - case 0x00: /* Empty Partition */ - partition_get_info = nullptr; - break; - - case 0x01: /* FAT12 */ - case 0x04: /* FAT16 (-32 MB) */ - case 0x06: /* FAT16 (32+ MB) */ - case 0x0B: /* FAT32 */ - case 0x0C: /* FAT32 (LBA Mapped) */ - case 0x0E: /* FAT16 (LBA Mapped) */ - case 0x11: /* OS/2 FAT12 */ - case 0x14: /* OS/2 FAT16 (-32 MB) */ - case 0x16: /* OS/2 FAT16 (32+ MB) */ - case 0x1B: /* Hidden Win95 FAT32 */ - case 0x1C: /* Hidden Win95 FAT32 (LBA Mapped) */ - case 0x1D: /* Hidden Win95 FAT16 (LBA Mapped) */ - case 0xC1: /* DR-DOS FAT12 */ - case 0xC4: /* DR-DOS FAT16 (-32 MB) */ - case 0xC6: /* DR-DOS FAT16 (32+ MB) */ - case 0xD1: /* Old Multiuser DOS FAT12 */ - case 0xD4: /* Old Multiuser DOS FAT16 (-32 MB) */ - case 0xD6: /* Old Multiuser DOS FAT16 (32+ MB) */ - partition_get_info = fat_get_info; - break; - - default: - partition_get_info = unknown_partition_get_info; - break; - } - - partitions.emplace_back( - partition_get_info, - info->partitions[i].sector_index, - info->partitions[i].total_sectors); - } - return IMGTOOLERR_SUCCESS; -} - - - -void pc_chd_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_BLOCK_SIZE: info->i = FAT_SECLEN; break; - case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES: info->i = sizeof(pc_chd_image_info); break; - case IMGTOOLINFO_INT_TRACKS_ARE_CALLED_CYLINDERS: info->i = 1; break; - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "pc_chd"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "PC CHD disk image"); break; - case IMGTOOLINFO_STR_FILE_EXTENSIONS: strcpy(info->s = imgtool_temp_str(), "chd"); break; - case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC: strcpy(info->s = imgtool_temp_str(), pc_chd_create_optionspec); break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case IMGTOOLINFO_PTR_CREATE: info->create = pc_chd_image_create; break; - case IMGTOOLINFO_PTR_OPEN: info->open = pc_chd_image_open; break; - case IMGTOOLINFO_PTR_CLOSE: info->close = pc_chd_image_close; break; - case IMGTOOLINFO_PTR_READ_SECTOR: info->read_sector = pc_chd_image_readsector; break; - case IMGTOOLINFO_PTR_WRITE_SECTOR: info->write_sector = pc_chd_image_writesector; break; - case IMGTOOLINFO_PTR_READ_BLOCK: info->read_block = pc_chd_image_readblock; break; - case IMGTOOLINFO_PTR_WRITE_BLOCK: info->write_block = pc_chd_image_writeblock; break; - case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE: info->createimage_optguide = &pc_chd_create_optionguide; break; - case IMGTOOLINFO_PTR_GET_GEOMETRY: info->get_geometry = pc_chd_image_get_geometry; break; - case IMGTOOLINFO_PTR_LIST_PARTITIONS: info->list_partitions = pc_chd_list_partitions; break; - } -} diff --git a/src/tools/imgtool/modules/prodos.cpp b/src/tools/imgtool/modules/prodos.cpp deleted file mode 100644 index e196d53..0000000 --- a/src/tools/imgtool/modules/prodos.cpp +++ /dev/null @@ -1,2270 +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" - -#include "opresolv.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, std::size(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 &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 deleted file mode 100644 index 0076500..0000000 --- a/src/tools/imgtool/modules/psion.cpp +++ /dev/null @@ -1,698 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Sandro Ronco -/*************************************************************************** - - Psion Organiser II Datapack - - 08/18/2010 Sandro Ronco - - Known file types: - 0x00 invalid record - 0x01 - 0x7e deleted record - 0x7f invalid deleted record - 0x80 long record - 0x81 file name - 0x82 diary - 0x83 OPL/OB3 procedure - 0x84 RS232 setup - 0x85 - 0x8f reserved - 0x90 MAIN Record - 0x91 - 0xfe data records from files - 0xff invalid record - -****************************************************************************/ - -#include "imgtool.h" - -#include "opresolv.h" - -#include - -#define MAXFILES 256 - -struct psion_file -{ - char filename[9]; - uint8_t type; - uint8_t id; - - uint16_t name_rec; - uint16_t data_rec; -}; - -struct psion_pack -{ - imgtool::stream *stream; - - uint16_t eop; - struct psion_file pack_index[MAXFILES]; -}; - -struct psion_iter -{ - uint16_t index; -}; - -static psion_pack *get_psion_pack(imgtool::image &image) -{ - return (psion_pack*)image.extra_bytes(); -} - -uint16_t head_checksum(uint8_t* data) -{ - uint16_t checksum = 0; - - for (int i=0; i<6; i+=2) - checksum += (data[i]<<8 | data[i+1]); - - return checksum; -} - -uint16_t get_long_rec_size(imgtool::stream &stream) -{ - uint8_t size_h, size_l; - - stream.read(&size_h, 1); - stream.read(&size_l, 1); - - return (size_h<<8) | size_l; -} - -uint32_t update_pack_index(psion_pack *pack) -{ - uint8_t data, type; - uint16_t size; - uint16_t index = 0; - - memset(pack->pack_index, 0, sizeof(psion_file) * MAXFILES); - - // start at the first record - pack->stream->seek(0x10, SEEK_SET); - - do - { - pack->stream->read(&data, 1); - - if(data == 0xff) - { - pack->eop = pack->stream->tell() - 1; - return true; - } - else if (data == 0x02) - { - // long record without name are ignored - pack->stream->read(&data, 1); - size = get_long_rec_size(*pack->stream); - pack->stream->seek(size, SEEK_CUR); - } - else - { - pack->stream->read(&type, 1); - - // deleted record are not listed - if (type < 0x90 && (type & 0x80)) - { - pack->pack_index[index].type = type; - pack->stream->read(&pack->pack_index[index].filename, 8); - pack->stream->read(&pack->pack_index[index].id, 1); - pack->pack_index[index].name_rec = pack->stream->tell() - 11; - - //check for data record - pack->stream->read(&data, 1); - if (data == 0x02) - pack->pack_index[index].data_rec = pack->stream->tell() - 1; - - pack->stream->seek(-1, SEEK_CUR); - - index++; - } - else - pack->stream->seek(data, SEEK_CUR); - } - - } while (pack->stream->size() > pack->stream->tell()); - - // corrupted image - return false; -} - -int seek_next_record(imgtool::stream &stream, uint8_t id) -{ - uint8_t data, rec_id; - uint16_t size; - - do - { - stream.read(&data, 1); - - if(data == 0xff) - break; - - if (data == 2) - { - stream.read(&rec_id, 1); - size = get_long_rec_size(stream); - - } - else - { - stream.read(&rec_id, 1); - if (id == rec_id) - { - stream.seek(-2, SEEK_CUR); - return true; - } - size = data; - } - - // next record - stream.seek(size, SEEK_CUR); - - } while (stream.size() > stream.tell()); - - return false; -} - -// if there are multiple files with the same name, only the first is found -int seek_file_name(psion_pack *pack, const char *filename) -{ - uint16_t index = 0; - - while (pack->pack_index[index].name_rec) - { - if (!strncmp(filename, pack->pack_index[index].filename, strlen(filename))) - return index; - index++; - } - - // filename not found - return -1; -} - -uint8_t get_free_file_id(psion_pack *pack) -{ - for (uint8_t file_id=0x91; file_id<0xff; file_id++) - { - int index = 0; - - while (pack->pack_index[index].id != file_id) - if (pack->pack_index[index++].name_rec == 0) - return file_id; - } - - return 0xff; -} - -static void put_name_record(imgtool::stream &stream, const char* filename, uint8_t record_type, uint8_t record_id) -{ - char data[0x10]; - int i = 0; - - data[i++] = 0x09; - data[i++] = record_type; - - // filename is 8 char long space filled - for (int j=0; j<8; j++) - if (j < strlen(filename)) - data[i++] = filename[j]; - else - data[i++] = 0x20; - - data[i++] = record_id; - - stream.write(data, i); -} - -static void update_opk_head(imgtool::stream &stream) -{ - uint16_t size = stream.size() - 6; - - stream.seek(4, SEEK_SET); - stream.putc((size>>8) & 0xff); - stream.putc(size & 0xff); -} - -char *stream_getline(imgtool::stream &source, uint16_t max_len) -{ - uint16_t pos = 0; - char data; - char *line = (char*)malloc(max_len); - memset(line, 0, max_len); - - while (pos < max_len && source.size() > source.tell()) - { - source.read(&data, 1); - - switch(data) - { - case '\r': - source.read(&data, 1); - if (data != '\n') - source.seek(-1, SEEK_CUR); - [[fallthrough]]; - case '\n': - return line; - default: - line[pos++] = data; - break; - } - } - - if (pos) - return line; - - free(line); - return NULL; -} - -uint16_t put_odb(imgtool::stream &instream, imgtool::stream &outstream, uint8_t file_id) -{ - char *line; - uint16_t out_size = 0; - - // reset stream - instream.seek(0, SEEK_SET); - - while ((line = stream_getline(instream, 256))) - { - uint16_t len = strlen(line); - - outstream.putc((uint8_t)len); - outstream.putc(file_id); - outstream.write(line, len); - - out_size += (len + 1); - - free(line); - } - - // end of pack - outstream.fill(0xff, 2); - - return out_size + 4; -} - -uint16_t put_ob3(imgtool::stream &instream, imgtool::stream &outstream) -{ - uint16_t size = instream.size() - 6; - std::vector buffer(size); - - instream.seek(6, SEEK_SET); - instream.read(&buffer[0], size); - - outstream.write(&buffer[0], size); - - // end of pack - outstream.fill(0xff, 2); - - return size; -} - -uint16_t put_opl(imgtool::stream &instream, imgtool::stream &outstream) -{ - uint16_t out_size = 0; - uint32_t rec_start = outstream.tell(); - char *line; - - // reset stream - instream.seek(0, SEEK_SET); - - outstream.fill(0x00, 4); - - // replace all eol with 0x00 - while ((line = stream_getline(instream, 256))) - { - // replace tab with space - for (int i=0; i>8) & 0xff); - outstream.putc(out_size & 0xff); - - return out_size + 4; -} - -uint16_t get_odb(imgtool::stream &instream, imgtool::stream &outstream, uint8_t type, uint8_t file_id) -{ - uint8_t data, *buffer; - uint16_t out_size = 0; - - if (file_id >= 0x90) - while (seek_next_record(instream, file_id)) - { - instream.read(&data, 1); - instream.seek(1, SEEK_CUR); - buffer = (uint8_t*)malloc(data); - instream.read(buffer, data); - outstream.write(buffer, data); - outstream.putc('\r'); - outstream.putc('\n'); - free (buffer); - out_size += data; - } - - return out_size; -} - -uint16_t get_ob3(imgtool::stream &instream, imgtool::stream &outstream, uint8_t type, uint8_t file_id) -{ - uint8_t data, *buffer = NULL; - uint16_t size = 0; - static const char ob3_magic[3] = {'O', 'R', 'G'}; - - instream.read(&data, 1); - - if (data == 0x02) - { - instream.seek(1, SEEK_CUR); - size = get_long_rec_size(instream); - buffer = (uint8_t*)malloc(size); - instream.read(buffer, size); - } - - outstream.write(ob3_magic, 3); - outstream.putc((size>>8) & 0xff); - outstream.putc(size & 0xff); - outstream.putc(type | 0x80); - - if (buffer) - { - outstream.write(buffer, size); - free (buffer); - } - - return size; -} - -static imgtoolerr_t datapack_open(imgtool::image &image, imgtool::stream::ptr &&stream) -{ - psion_pack *pack = get_psion_pack(image); - char opk_magic[4]; - - stream->read(opk_magic, 4); - - if(strcmp(opk_magic, "OPK\0")) - return IMGTOOLERR_UNEXPECTED; - - pack->stream = stream.get(); - - if (update_pack_index(pack)) - { - pack->stream = stream.release(); - return IMGTOOLERR_SUCCESS; - } - else - { - return IMGTOOLERR_CORRUPTIMAGE; - } -} - -static imgtoolerr_t datapack_create(imgtool::image &image, imgtool::stream::ptr &&stream, util::option_resolution *opts) -{ - psion_pack *pack = get_psion_pack(image); - static const uint8_t opk_magic[4] = {'O', 'P', 'K', 0x00}; - uint8_t pack_head[8] = {0x40, 0x00, 0x59, 0x01, 0x01, 0x01, 0x00, 0x00}; - uint16_t checksum; - - pack_head[0] |= (opts->lookup_int('R')) ? 0x00 : 0x02; - pack_head[0] |= (opts->lookup_int('P')) ? 0x04 : 0x00; - pack_head[0] |= (opts->lookup_int('W')) ? 0x00 : 0x08; - pack_head[0] |= (opts->lookup_int('B')) ? 0x00 : 0x10; - pack_head[0] |= (opts->lookup_int('C')) ? 0x20 : 0x00; - pack_head[1] = opts->lookup_int('S'); - - checksum = head_checksum(pack_head); - - stream->write(opk_magic, 4); - stream->fill(0x00, 2); - stream->write(pack_head, 8); - - stream->putc((checksum>>8) & 0xff); - stream->putc(checksum & 0xff); - - put_name_record(*stream, "MAIN", 0x81, 0x90); - - stream->fill(0xff, 2); - - update_opk_head(*stream); - - pack->stream = stream.get(); - - if (update_pack_index(pack)) - { - pack->stream = stream.release(); - return IMGTOOLERR_SUCCESS; - } - else - { - return IMGTOOLERR_CORRUPTIMAGE; - } -} - -static void datapack_close(imgtool::image &image) -{ - psion_pack *pack = get_psion_pack(image); - - delete pack->stream; -} - -static imgtoolerr_t datapack_begin_enum(imgtool::directory &enumeration, const char *path) -{ - psion_iter *iter = (psion_iter*)enumeration.extra_bytes(); - iter->index = 0; - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t datapack_next_enum(imgtool::directory &enumeration, imgtool_dirent &ent) -{ - imgtool::image &image(enumeration.image()); - psion_pack *pack = get_psion_pack(image); - psion_iter *iter = (psion_iter*)enumeration.extra_bytes(); - uint8_t data = 0; - - if (!pack->pack_index[iter->index].name_rec) - { - ent.eof = 1; - 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); - - if (pack->pack_index[iter->index].data_rec) - { - pack->stream->seek(pack->pack_index[iter->index].data_rec + 2, SEEK_SET); - ent.filesize = get_long_rec_size(*pack->stream); - } - - // seek all file's records - if (pack->pack_index[iter->index].id >= 0x90) - { - pack->stream->seek(0x10, SEEK_SET); - while (seek_next_record(*pack->stream, pack->pack_index[iter->index].id)) - { - pack->stream->read(&data, 1); - pack->stream->seek(data + 1, SEEK_CUR); - ent.filesize +=data; - } - } - - iter->index++; - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t datapack_free_space(imgtool::partition &partition, uint64_t *size) -{ - imgtool::image &image(partition.image()); - psion_pack *pack = get_psion_pack(image); - uint32_t pack_size = 0; - - pack->stream->seek(0x07, SEEK_SET); - pack->stream->read(&pack_size, 1); - - if (size) - *size = (pack_size * 0x2000) - pack->eop; - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t datapack_read_file(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &destf) -{ - imgtool::image &image(partition.image()); - psion_pack *pack = get_psion_pack(image); - int index = seek_file_name(pack, filename); - - if (index >= 0) - { - if ((pack->pack_index[index].type & 0x7f) == 0x01) - { - // ODB files - pack->stream->seek(0x10, SEEK_SET); - get_odb(*pack->stream, destf, pack->pack_index[index].type, pack->pack_index[index].id); - } - else if ((pack->pack_index[index].type & 0x7f) == 0x03) - { - // OB3/OPL files - pack->stream->seek(pack->pack_index[index].data_rec, SEEK_SET); - get_ob3(*pack->stream, destf, pack->pack_index[index].type, pack->pack_index[index].id); - } - else - { - // Other files - return IMGTOOLERR_UNIMPLEMENTED; - } - - return IMGTOOLERR_SUCCESS; - } - else - return IMGTOOLERR_FILENOTFOUND; -} - -static imgtoolerr_t datapack_write_file(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &sourcef, util::option_resolution *opts) -{ - imgtool::image &image(partition.image()); - psion_pack *pack = get_psion_pack(image); - static const uint8_t data_head[4] = {0x02, 0x80, 0x00, 0x00}; - uint8_t head[3]; - uint16_t size = 0; - uint8_t type = opts->lookup_int('T'); - uint8_t file_id = opts->lookup_int('I'); - - if (!pack->eop) - return IMGTOOLERR_CORRUPTIMAGE; - - // if not file_id is specified get the first free (for ODB only) - if (file_id == 0 && type == 3) - { - file_id = get_free_file_id(pack); - - if (file_id == 0xff) - return IMGTOOLERR_NOSPACE; - } - - sourcef.read(head, 3); - pack->stream->seek(pack->eop, SEEK_SET); - - if (type == 0) - type = (!strncmp((char*)head, "ORG", 3)) ? 1 : 2; - - switch (type) - { - case 1: //OB3 file - put_name_record(*pack->stream, filename, 0x83, file_id); - pack->stream->write(data_head, 4); - size = put_ob3(sourcef, *pack->stream); - break; - case 2: //OPL file - put_name_record(*pack->stream, filename, 0x83, file_id); - pack->stream->write(data_head, 4); - size = put_opl(sourcef, *pack->stream); - break; - case 3: //ODB file - put_name_record(*pack->stream, filename, 0x81, file_id); - size = put_odb(sourcef, *pack->stream, file_id); - break; - } - - if (type != 3) - { - // update the OB3/OPL long record size - pack->stream->seek(pack->eop + 13, SEEK_SET); - pack->stream->putc((size>>8) & 0xff); - pack->stream->putc(size & 0xff); - } - - update_opk_head(*pack->stream); - - if (update_pack_index(pack)) - return IMGTOOLERR_SUCCESS; - else - return IMGTOOLERR_CORRUPTIMAGE; -} - -static imgtoolerr_t datapack_delete_file(imgtool::partition &partition, const char *filename) -{ - imgtool::image &image(partition.image()); - psion_pack *pack = get_psion_pack(image); - int index = seek_file_name(pack, filename); - - if (index >= 0) - { - // clear the bit 7 of the file type to mark the file as deleted - pack->stream->seek(pack->pack_index[index].name_rec + 1, SEEK_SET); - pack->stream->putc(pack->pack_index[index].type & 0x7f); - - if (update_pack_index(pack)) - return IMGTOOLERR_SUCCESS; - else - return IMGTOOLERR_CORRUPTIMAGE; - } - else - return IMGTOOLERR_FILENOTFOUND; -} - -OPTION_GUIDE_START( psion_create_optguide ) - OPTION_ENUM_START( 'S', "size", "datapack size" ) - OPTION_ENUM( 1, "8k", "8 kbyte" ) - OPTION_ENUM( 2, "16k", "16 kbyts" ) - OPTION_ENUM( 4, "32k", "32 kbyte" ) - OPTION_ENUM( 8, "64k", "64 kbyte" ) - OPTION_ENUM( 16, "128k", "128 kbyte" ) // only paged datapacks can have this size - OPTION_ENUM_END - OPTION_INT('R', "ram", "EPROM/RAM datapack" ) - OPTION_INT('P', "paged", "linear/paged datapack" ) - OPTION_INT('W', "protect", "write-protected datapack" ) - OPTION_INT('B', "boot", "bootable datapack" ) - OPTION_INT('C', "copy", "copyable datapack" ) -OPTION_GUIDE_END - -OPTION_GUIDE_START( psion_write_optguide ) - OPTION_ENUM_START( 'T', "type", "file type" ) - OPTION_ENUM( 1, "OB3", "OB3 files" ) - OPTION_ENUM( 2, "OPL", "OPL files" ) - OPTION_ENUM( 3, "ODB", "ODB or text files" ) - OPTION_ENUM_END - OPTION_INT( 'I', "id", "File ID" ) -OPTION_GUIDE_END - -void psion_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_IMAGE_EXTRA_BYTES : info->i = sizeof(psion_pack); break; - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES : info->i = sizeof(psion_iter); break; - - // --- the following bits of info are returned as pointers to data or functions --- - case IMGTOOLINFO_PTR_OPEN : info->open = datapack_open; break; - case IMGTOOLINFO_PTR_CREATE : info->create = datapack_create; break; - case IMGTOOLINFO_PTR_CLOSE : info->close = datapack_close; break; - case IMGTOOLINFO_PTR_BEGIN_ENUM : info->begin_enum = datapack_begin_enum; break; - case IMGTOOLINFO_PTR_NEXT_ENUM : info->next_enum = datapack_next_enum; break; - case IMGTOOLINFO_PTR_FREE_SPACE : info->free_space = datapack_free_space; break; - case IMGTOOLINFO_PTR_READ_FILE : info->read_file = datapack_read_file; break; - case IMGTOOLINFO_PTR_WRITE_FILE : info->write_file = datapack_write_file; break; - case IMGTOOLINFO_PTR_DELETE_FILE : info->delete_file = datapack_delete_file; break; - case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE : info->createimage_optguide = &psion_create_optguide; break; - case IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE : info->createimage_optguide = &psion_write_optguide; break; - - // --- the following bits of info are returned as NULL-terminated strings --- - case IMGTOOLINFO_STR_NAME : strcpy( info->s = imgtool_temp_str(), "psionpack"); break; - case IMGTOOLINFO_STR_DESCRIPTION : strcpy( info->s = imgtool_temp_str(), "Psion Organiser II Datapack"); break; - case IMGTOOLINFO_STR_FILE : strcpy( info->s = imgtool_temp_str(), __FILE__); break; - case IMGTOOLINFO_STR_FILE_EXTENSIONS : strcpy( info->s = imgtool_temp_str(), "opk"); break; - case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC : strcpy( info->s = imgtool_temp_str(), "S1/2/[4]/8/16;R[0]/1;P[0]/1;W0/[1];B[0]/1;C0/[1]"); break; - case IMGTOOLINFO_STR_WRITEFILE_OPTSPEC : strcpy( info->s = imgtool_temp_str(), "T[1]/2/3;I[0]/145-255"); break; - } -} diff --git a/src/tools/imgtool/modules/rsdos.cpp b/src/tools/imgtool/modules/rsdos.cpp deleted file mode 100644 index 09b8131..0000000 --- a/src/tools/imgtool/modules/rsdos.cpp +++ /dev/null @@ -1,666 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/**************************************************************************** - - rsdos.cpp - - CoCo RS-DOS disk images - -****************************************************************************/ - -#include "imgtool.h" -#include "filter.h" -#include "iflopimg.h" - -#include "formats/coco_dsk.h" -#include "corestr.h" -#include "opresolv.h" - -#include -#include -#include - -/* this structure mirrors the structure of an RS-DOS directory entry on disk */ -struct rsdos_dirent -{ - char filename[11]; - char ftype; - char asciiflag; - unsigned char first_granule; - unsigned char lastsectorbytes_msb; - unsigned char lastsectorbytes_lsb; - unsigned char unused[16]; -}; - -struct rsdos_direnum -{ - int index; - bool eof; -}; - -#define RSDOS_OPTIONS_FTYPE 'T' -#define RSDOS_OPTIONS_ASCII 'M' - - - -/********************************************************************* - Imgtool module code -*********************************************************************/ - -#define MAX_DIRENTS ((18-2)*(256/32)) -#define MAX_GRANULEMAP_SIZE 256 - -//------------------------------------------------- -// get_rsdos_dirent -//------------------------------------------------- - -static floperr_t get_rsdos_dirent(imgtool::image &f, int index_loc, rsdos_dirent &ent) -{ - return floppy_read_sector(imgtool_floppy(f), 0, 17, 3, index_loc * 32, (void *) &ent, sizeof(ent)); -} - - -//------------------------------------------------- -// put_rsdos_dirent -//------------------------------------------------- - -static floperr_t put_rsdos_dirent(imgtool::image &f, int index_loc, const rsdos_dirent &ent) -{ - if (index_loc >= MAX_DIRENTS) - return (floperr_t)IMGTOOLERR_FILENOTFOUND; - return floppy_write_sector(imgtool_floppy(f), 0, 17, 3, index_loc * 32, (void *) &ent, sizeof(ent), 0); /* TODO: pass ddam argument from imgtool */ -} - - -//------------------------------------------------- -// get_dirent_fname -//------------------------------------------------- - -static std::string get_dirent_fname(const rsdos_dirent &ent) -{ - return extract_padded_filename(ent.filename, 8, 3); -} - - -//------------------------------------------------- -// lookup_rsdos_file -//------------------------------------------------- - -static imgtoolerr_t lookup_rsdos_file(imgtool::image &f, const char *fname, rsdos_dirent &ent, int *position = nullptr) -{ - int i; - floperr_t ferr; - std::string fnamebuf; - - i = 0; - - do - { - do - { - ferr = get_rsdos_dirent(f, i++, ent); - if (ferr) - return imgtool_floppy_error(ferr); - } - while(ent.filename[0] == '\0'); - - - if (ent.filename[0] != -1) - fnamebuf = get_dirent_fname(ent); - } - while((ent.filename[0] != -1) && core_stricmp(fnamebuf.c_str(), fname)); - - if (ent.filename[0] == -1) - return IMGTOOLERR_FILENOTFOUND; - - if (position) - *position = i - 1; - return (imgtoolerr_t)0; -} - - -//------------------------------------------------- -// get_granule_count -//------------------------------------------------- - -static uint8_t get_granule_count(imgtool::image &img) -{ - uint16_t tracks; - uint16_t granules; - - tracks = floppy_get_tracks_per_disk(imgtool_floppy(img)); - granules = (tracks - 1) * 2; - return (granules > 255) ? 255 : (uint8_t) granules; -} - - -//------------------------------------------------- -// get_granule_map -//------------------------------------------------- - -static floperr_t get_granule_map(imgtool::image &img, uint8_t *granule_map, uint8_t granule_count[MAX_GRANULEMAP_SIZE]) -{ - uint8_t count; - - count = get_granule_count(img); - if (granule_count) - *granule_count = count; - - return floppy_read_sector(imgtool_floppy(img), 0, 17, 2, 0, granule_map, count); -} - - -//------------------------------------------------- -// put_granule_map -//------------------------------------------------- - -static floperr_t put_granule_map(imgtool::image &img, const uint8_t *granule_map, uint8_t granule_count) -{ - return floppy_write_sector(imgtool_floppy(img), 0, 17, 2, 0, granule_map, granule_count, 0); /* TODO: pass ddam argument from imgtool */ -} - - -//------------------------------------------------- -// transfer_granule -//------------------------------------------------- - -static imgtoolerr_t transfer_granule(imgtool::image &img, uint8_t granule, int length, imgtool::stream &f, imgtoolerr_t (*proc)(imgtool::image &, int, int, int, int, size_t, imgtool::stream &)) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - uint8_t track, sector; - - track = granule / 2; - if (track >= 17) - track++; - - sector = (granule % 2) ? 10 : 1; - - if (length > 0) - err = proc(img, 0, track, sector, 0, length, f); - return err; -} - - -//------------------------------------------------- -// transfer_from_granule -//------------------------------------------------- - -static imgtoolerr_t transfer_from_granule(imgtool::image &img, uint8_t granule, int length, imgtool::stream &destf) -{ - return transfer_granule(img, granule, length, destf, imgtool_floppy_read_sector_to_stream); -} - - -//------------------------------------------------- -// transfer_to_granule -//------------------------------------------------- - -static imgtoolerr_t transfer_to_granule(imgtool::image &img, uint8_t granule, int length, imgtool::stream &sourcef) -{ - return transfer_granule(img, granule, length, sourcef, imgtool_floppy_write_sector_from_stream); -} - - -//------------------------------------------------- -// process_rsdos_file -//------------------------------------------------- - -static imgtoolerr_t process_rsdos_file(struct rsdos_dirent *ent, imgtool::image &img, imgtool::stream *destf, size_t &size) -{ - floperr_t ferr; - size_t s, lastgransize; - uint8_t granule_count; - unsigned char i = 0, granule; - uint8_t usedmap[MAX_GRANULEMAP_SIZE]; // used to detect infinite loops - uint8_t granule_map[MAX_GRANULEMAP_SIZE]; - - ferr = get_granule_map(img, granule_map, &granule_count); - if (ferr) - return imgtool_floppy_error(ferr); - - memset(usedmap, 0, granule_count); - - lastgransize = ent->lastsectorbytes_lsb + (((int) ent->lastsectorbytes_msb) << 8); - s = 0; - granule = ent->first_granule; - - while(!usedmap[granule] && ((i = granule_map[granule]) < granule_count)) - { - usedmap[granule] = 1; - if (destf) - transfer_from_granule(img, granule, 9*256, *destf); - - /* i is the next granule */ - s += (256 * 9); - granule = i; - } - - if ((i < 0xc0) || (i > 0xc9)) - return IMGTOOLERR_CORRUPTIMAGE; - - if (lastgransize) - i--; - lastgransize += (256 * (i - 0xc0)); - - if (destf) - transfer_from_granule(img, granule, lastgransize, *destf); - - size = s + lastgransize; - return IMGTOOLERR_SUCCESS; -} - - -//------------------------------------------------- -// prepare_dirent - create a new directory entry -// with a specified name -//------------------------------------------------- - -static imgtoolerr_t prepare_dirent(rsdos_dirent &ent, const char *fname) -{ - const char *fname_end; - const char *fname_ext; - int fname_ext_len; - - memset(&ent, '\0', sizeof(ent)); - memset(ent.filename, ' ', sizeof(ent.filename)); - - 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.filename[0], fname, fname_end - fname); - memcpy(&ent.filename[8], fname_ext, fname_ext_len); - - // for now, all files are type 2 binary files - ent.ftype = 2; - ent.asciiflag = 0; - return IMGTOOLERR_SUCCESS; -} - - -//------------------------------------------------- -// rsdos_diskimage_nextenum -//------------------------------------------------- - -static imgtoolerr_t rsdos_diskimage_nextenum(imgtool::directory &enumeration, imgtool_dirent &ent) -{ - floperr_t ferr; - imgtoolerr_t err; - size_t filesize; - rsdos_direnum *rsenum; - rsdos_dirent rsent; - - imgtool::image &image(enumeration.image()); - rsenum = (rsdos_direnum *) enumeration.extra_bytes(); - - /* Did we hit the end of file before? */ - if (rsenum->eof) - goto eof; - - do - { - if (rsenum->index >= MAX_DIRENTS) - goto eof; - - ferr = get_rsdos_dirent(image, rsenum->index++, rsent); - if (ferr) - return imgtool_floppy_error(ferr); - } - while(rsent.filename[0] == '\0'); - - // now are we at the eof point? - if (rsent.filename[0] == -1) - { - rsenum->eof = 1; -eof: - ent.eof = 1; - } - else - { - /* Note the end of file */ - err = process_rsdos_file(&rsent, image, nullptr, 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(rsent); - - 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; -} - - -//------------------------------------------------- -// rsdos_diskimage_freespace -//------------------------------------------------- - -static imgtoolerr_t rsdos_diskimage_freespace(imgtool::partition &partition, uint64_t *size) -{ - floperr_t ferr; - uint8_t i; - size_t s = 0; - uint8_t granule_count; - uint8_t granule_map[MAX_GRANULEMAP_SIZE]; - imgtool::image &image(partition.image()); - - ferr = get_granule_map(image, granule_map, &granule_count); - if (ferr) - return imgtool_floppy_error(ferr); - - for (i = 0; i < granule_count; i++) - { - if (granule_map[i] == 0xff) - s += (9 * 256); - } - *size = s; - return (imgtoolerr_t)FLOPPY_ERROR_SUCCESS; -} - - -//------------------------------------------------- -// delete_entry -//------------------------------------------------- - -static imgtoolerr_t delete_entry(imgtool::image &img, rsdos_dirent &ent, int pos) -{ - floperr_t ferr; - unsigned char g, i; - uint8_t granule_count; - uint8_t granule_map[MAX_GRANULEMAP_SIZE]; - - // write a NUL in the filename, marking it deleted - ent.filename[0] = 0; - ferr = put_rsdos_dirent(img, pos, ent); - if (ferr) - return imgtool_floppy_error(ferr); - - ferr = get_granule_map(img, granule_map, &granule_count); - if (ferr) - return imgtool_floppy_error(ferr); - - // now free up the granules - g = ent.first_granule; - while (g < granule_count) - { - i = granule_map[g]; - granule_map[g] = 0xff; - g = i; - } - - ferr = put_granule_map(img, granule_map, granule_count); - if (ferr) - return imgtool_floppy_error(ferr); - - return IMGTOOLERR_SUCCESS; -} - - -//------------------------------------------------- -// rsdos_diskimage_readfile -//------------------------------------------------- - -static imgtoolerr_t rsdos_diskimage_readfile(imgtool::partition &partition, const char *fname, const char *fork, imgtool::stream &destf) -{ - imgtoolerr_t err; - struct rsdos_dirent ent; - size_t size; - imgtool::image &img(partition.image()); - - err = lookup_rsdos_file(img, fname, ent); - if (err) - return err; - - err = process_rsdos_file(&ent, img, &destf, size); - if (err) - return err; - - if (size == (size_t) -1) - return IMGTOOLERR_CORRUPTIMAGE; - - return (imgtoolerr_t)0; -} - - -//------------------------------------------------- -// rsdos_diskimage_writefile -//------------------------------------------------- - -static imgtoolerr_t rsdos_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 &img(partition.image()); - struct rsdos_dirent ent, ent2; - size_t i; - uint64_t sz; - uint64_t freespace = 0; - unsigned char g; - unsigned char *gptr; - uint8_t granule_count; - uint8_t granule_map[MAX_GRANULEMAP_SIZE]; - - // can we write to this image? - if (floppy_is_read_only(imgtool_floppy(img))) - return IMGTOOLERR_READONLY; - - err = rsdos_diskimage_freespace(partition, &freespace); - if (err) - return err; - - // is there enough space? - sz = sourcef.size(); - if (sz > freespace) - return IMGTOOLERR_NOSPACE; - - // setup our directory entry - err = prepare_dirent(ent, fname); - if (err) - return err; - - ent.ftype = writeoptions->lookup_int(RSDOS_OPTIONS_FTYPE); - ent.asciiflag = uint8_t(writeoptions->lookup_int(RSDOS_OPTIONS_ASCII)) - 1; - ent.lastsectorbytes_lsb = sz % 256; - ent.lastsectorbytes_msb = (((sz % 256) == 0) && (sz > 0)) ? 1 : 0; - gptr = &ent.first_granule; - - ferr = get_granule_map(img, granule_map, &granule_count); - if (ferr) - return imgtool_floppy_error(ferr); - - g = 0x00; - - do - { - while (granule_map[g] != 0xff) - { - g++; - if ((g >= granule_count) || (g == 0)) - return IMGTOOLERR_UNEXPECTED; // we should have already verified that there is enough space - } - *gptr = g; - gptr = &granule_map[g]; - - - i = std::min(sz, uint64_t(9*256)); - err = transfer_to_granule(img, g, i, sourcef); - if (err) - return err; - - sz -= i; - - // go to next granule - g++; - } - while(sz > 0); - - // now that we are done with the file, we need to specify the final entry - // in the file allocation table - *gptr = 0xc0 + ((i + 255) / 256); - - // now we need to find an empty directory entry - i = -1; - do - { - ferr = get_rsdos_dirent(img, ++i, ent2); - if (ferr) - return imgtool_floppy_error(ferr); - } - while((ent2.filename[0] != '\0') && strcmp(ent.filename, ent2.filename) && (ent2.filename[0] != -1)); - - // delete file if it already exists - if (ent2.filename[0] && (ent2.filename[0] != -1)) - { - err = delete_entry(img, ent2, i); - if (err) - return err; - } - - ferr = put_rsdos_dirent(img, i, ent); - if (ferr) - return imgtool_floppy_error(ferr); - - // write the granule map back out - ferr = put_granule_map(img, granule_map, granule_count); - if (ferr) - return imgtool_floppy_error(ferr); - - return IMGTOOLERR_SUCCESS; -} - - -//------------------------------------------------- -// rsdos_diskimage_deletefile -//------------------------------------------------- - -static imgtoolerr_t rsdos_diskimage_deletefile(imgtool::partition &partition, const char *fname) -{ - imgtoolerr_t err; - imgtool::image &image(partition.image()); - int pos; - struct rsdos_dirent ent; - - err = lookup_rsdos_file(image, fname, ent, &pos); - if (err) - return err; - - return delete_entry(image, ent, pos); -} - - -//------------------------------------------------- -// rsdos_diskimage_suggesttransfer -//------------------------------------------------- - -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()); - struct rsdos_dirent ent; - int pos; - - if (fname) - { - err = lookup_rsdos_file(image, fname, ent, &pos); - if (err) - return err; - - if (ent.asciiflag == (char) 0xFF) - { - /* ASCII file */ - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = filter_eoln_getinfo; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = NULL; - } - else if (ent.ftype == 0) - { - /* tokenized BASIC file */ - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = filter_cocobas_getinfo; - } - } - else - { - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = filter_eoln_getinfo; - suggestions[2].viability = SUGGESTION_POSSIBLE; - suggestions[2].filter = filter_cocobas_getinfo; - } - - return IMGTOOLERR_SUCCESS; -} - - - -/********************************************************************* - Imgtool module declaration -*********************************************************************/ - -OPTION_GUIDE_START( coco_rsdos_writefile_optionguide ) - OPTION_ENUM_START( RSDOS_OPTIONS_FTYPE, "ftype", "File type" ) - OPTION_ENUM( 0, "basic", "Basic" ) - OPTION_ENUM( 1, "data", "Data" ) - OPTION_ENUM( 2, "binary", "Binary" ) - OPTION_ENUM( 3, "assembler", "Assembler Source" ) - OPTION_ENUM_END - OPTION_ENUM_START( RSDOS_OPTIONS_ASCII, "ascii", "Ascii flag" ) - OPTION_ENUM( 0, "ascii", "Ascii" ) - OPTION_ENUM( 1, "binary", "Binary" ) - OPTION_ENUM_END -OPTION_GUIDE_END - - - -void rsdos_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 rsdos_direnum); break; - - /* --- the following bits of info are returned as NULL-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; - case IMGTOOLINFO_STR_EOLN: strcpy(info->s = imgtool_temp_str(), "\r"); break; - case IMGTOOLINFO_STR_WRITEFILE_OPTSPEC: strcpy(info->s = imgtool_temp_str(), "T0-[2]-3;M0-[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_NEXT_ENUM: info->next_enum = rsdos_diskimage_nextenum; break; - case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = rsdos_diskimage_freespace; break; - case IMGTOOLINFO_PTR_READ_FILE: info->read_file = rsdos_diskimage_readfile; break; - case IMGTOOLINFO_PTR_WRITE_FILE: info->write_file = rsdos_diskimage_writefile; break; - case IMGTOOLINFO_PTR_DELETE_FILE: info->delete_file = rsdos_diskimage_deletefile; break; - case IMGTOOLINFO_PTR_SUGGEST_TRANSFER: info->suggest_transfer = rsdos_diskimage_suggesttransfer; break; - case IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE: info->writefile_optguide = &coco_rsdos_writefile_optionguide; break; - case IMGTOOLINFO_PTR_FLOPPY_FORMAT: info->p = (void *) floppyoptions_coco; break; - } -} diff --git a/src/tools/imgtool/modules/rt11.cpp b/src/tools/imgtool/modules/rt11.cpp deleted file mode 100644 index be65355..0000000 --- a/src/tools/imgtool/modules/rt11.cpp +++ /dev/null @@ -1,690 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Sergey Svishchev -/**************************************************************************** - - rt11.cpp - - DEC RT-11 disk images - - References: - - VaFFM -- bitsavers://pdf/dec/pdp11/rt11/v5.6_Aug91/AA-PD6PA-TC_RT-11_Volume_and_File_Formats_Manual_Aug91.pdf - DHM -- bitsavers://pdf/dec/pdp11/rt11/v5.6_Aug91/AA-PE7VA-TC_RT-11_Device_Handlers_Manual_Aug91.pdf - SSM -- bitsavers://pdf/dec/pdp11/rt11/v5.0_Mar83/AA-H379B-TC_5.0_SWsuppMar83.pdf - TSX+ -- bitsavers://pdf/dec/pdp11/tsxPlus/manuals_6.31/TSX-Plus_UsersRef_Jan88.pdf - PUTR -- http://www.dbit.com/pub/putr/putr.asm - - To do: - - filter for text files - - read-write support - - report empty 'last modified' time if date field is all zeros - - report free space - - arbitrary sized images - - don't crash when strings in home block have non-ascii chars (charconverter does not apply) - - do something about bootblock bug in imgtool (commit aca90520) - - LBN Contents - --- -------- - 0 Reserved (primary bootstrap) - 1 Reserved (home block) - 2-5 Reserved (secondary bootstrap) - 6-7 Directory segment 1 - ... Directory segment 2-n - ... Data - - Home block - ---------- - 000-201 Bad block replacement table - 202-203 ? - 204-251 INITIALIZE/RESTORE data area - 252-273 BUP information area - 274-677 ? - 700-701 (Reserved for Digital, must be zero) - 702-703 (Reserved for Digital, must be zero) - 704-721 ? - 722-723 Pack cluster size (= 1) - 724-725 Block number of first directory segment - 726-727 System version (RAD50) - 730-742 Volume Identification - 744-757 Owner name - 760-773 System Identification - 776-777 Checksum - - Directory segment header - ------------------------ - 0 The total number of segments in this directory. - 1 The segment number of the next logical directory segment. If this word is 0, there are no more segments in the list. - 2 The number of the highest segment currently in use. Valid only in the first directory segment. - 3 The number of extra bytes per directory entry, always an unsigned, even octal number. - 4 The block number on the volume where the actual stored data identified by this segment begins. - - Directory entry - --------------- - 0 Status word - 1 File name 1-3 (RAD50) - 2 File name 4-6 (RAD50) - 3 File type 1-3 (RAD50) - 4 Total file length (blocks) - 5 Job#, Channel# (RT-11 uses this information only for tentative files) - 6 Creation date - 7- Optional extra words - -****************************************************************************/ - -#include "imgtool.h" -#include "formats/imageutl.h" -#include "iflopimg.h" - -#include -#include -#include - - -namespace -{ - struct rt11_diskinfo - { - uint16_t directory_start; - uint16_t total_segments; - uint16_t last_segment; - uint16_t dirent_size; - int dirents_per_block; - // autodetected - int tracks; - int heads; - int sectors; - uint32_t sector_size; - // cache - int map[16]; - int cached_track; - int cached_head; - }; - - enum misc_t - { - HOME_BLOCK = 1, - BLOCK_SIZE = 512 - }; - - struct rt11_direnum - { - uint8_t segment_data[2 * BLOCK_SIZE]; - uint16_t segment; - uint16_t index; - uint16_t data; - }; - - struct rt11_dirent - { - uint16_t status; - uint16_t filename[3]; - uint16_t time; - // synthetic - uint64_t filesize; - uint16_t data; - }; - - enum rt11_status - { - E_PRE = 0000020, - E_TENT = 0000400, - E_MPTY = 0001000, - E_PERM = 0002000, - E_EOS = 0004000, - E_READ = 0040000, - E_PROT = 0100000 - }; - - enum creation_policy_t - { - CREATE_NONE, - CREATE_FILE, - }; - - - util::arbitrary_datetime _rt11_crack_time(uint16_t rt11_time) - { - util::arbitrary_datetime dt; - - dt.second = 0; - dt.minute = 0; - dt.hour = 0; - dt.day_of_month = (rt11_time >> 5) & 31; - dt.month = (rt11_time >> 10) & 15; - dt.year = 1972 + (rt11_time & 31) + 32 * ((rt11_time >> 14) & 3); - - return dt; - } - - imgtool::datetime rt11_crack_time(uint16_t rt11_time) - { - util::arbitrary_datetime dt; - imgtool::datetime it; - - if (rt11_time == 0) - { - return imgtool::datetime(imgtool::datetime::datetime_type::NONE, dt); - } - - dt = _rt11_crack_time(rt11_time); - - it = imgtool::datetime(imgtool::datetime::datetime_type::LOCAL, dt); - - return it; - } - - void rt11_from_rad50(char *ascii, uint16_t *rad50, int num) - { - const char rad[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$.%0123456789:"; - - for (int i = 0, j = 0; i < num; i++) - { - ascii[j++] = rad[ rad50[i] / (050 * 050)]; - ascii[j++] = rad[(rad50[i] / 050) % 050]; - ascii[j++] = rad[ rad50[i] % 050]; - } - } - - void rt11_filename_from_rad50(char *ascii, uint16_t *rad50) - { - int i, j; - - rt11_from_rad50(&ascii[0], &rad50[0], 2); - for (i = 0; i < 6; i++) - { - if (ascii[i] == ' ') break; - } - ascii[i++] = '.'; - rt11_from_rad50(&ascii[i], &rad50[2], 1); - for (j = i; j < i + 3; j++) - { - if (ascii[j] == ' ') break; - } - ascii[j] = '\0'; - } - - int is_file_storagetype(uint16_t status) - { - return !(status & (E_MPTY | E_EOS | E_TENT)); - } - - rt11_diskinfo *get_rt11_info(imgtool::image &image) - { - return (rt11_diskinfo *)imgtool_floppy_extrabytes(image); - } -} - - -static imgtoolerr_t rt11_image_get_geometry(imgtool::image &image, uint32_t *tracks, uint32_t *heads, uint32_t *sectors) -{ - const rt11_diskinfo *di = get_rt11_info(image); - - *sectors = di->sectors; - *heads = di->heads; - *tracks = di->tracks; - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t rt11_get_sector_position(imgtool::image &image, uint32_t sector_index, - uint32_t &head, uint32_t &track, uint32_t §or) -{ - imgtoolerr_t err; - rt11_diskinfo *di = get_rt11_info(image); - uint32_t tracks, heads, sectors; - - err = image.get_geometry(&tracks, &heads, §ors); - if (err) - return err; - - track = sector_index / sectors / heads; - head = (sector_index / sectors) % heads; - - // map 1-based sector numbers, possibly interleaved, to sector indexes - if (track != di->cached_track || head != di->cached_head) - { - memset(di->map, -1, sizeof(di->map)); - for (int i = 0; i < 256; i++) - { - int sector_id; - - if (floppy_get_indexed_sector_info(imgtool_floppy(image), head, track, i, NULL, NULL, §or_id, NULL, NULL)) - continue; - - if (sector_id > 0 && sector_id <= sectors) - di->map[sector_id - 1] = i; - } - di->cached_track = track; - di->cached_head = head; - } - - if (di->map[(sector_index % sectors)] < 0) - { - return IMGTOOLERR_SEEKERROR; - } - else - { - sector = di->map[(sector_index % sectors)]; - return IMGTOOLERR_SUCCESS; - } -} - - -static imgtoolerr_t rt11_image_readblock(imgtool::image &image, void *buffer, uint64_t block) -{ - imgtoolerr_t err; - floperr_t ferr; - const rt11_diskinfo *di = get_rt11_info(image); - uint32_t track, head, sector; - unsigned long flags; - - if (di->sector_size == 256) - { - err = rt11_get_sector_position(image, block * 2, head, track, sector); - if (err) - return err; - - ferr = floppy_read_indexed_sector(imgtool_floppy(image), head, track, sector, 0, buffer, 256); - if (ferr) - return imgtool_floppy_error(ferr); - - ferr = floppy_get_indexed_sector_info(imgtool_floppy(image), head, track, sector, NULL, NULL, NULL, NULL, &flags); - if (ferr) - return imgtool_floppy_error(ferr); - - if (flags) - return IMGTOOLERR_READERROR; - - err = rt11_get_sector_position(image, (block * 2) + 1, head, track, sector); - if (err) - return err; - - ferr = floppy_read_indexed_sector(imgtool_floppy(image), head, track, sector, 0, ((uint8_t *) buffer) + 256, 256); - if (ferr) - return imgtool_floppy_error(ferr); - - ferr = floppy_get_indexed_sector_info(imgtool_floppy(image), head, track, sector, NULL, NULL, NULL, NULL, &flags); - if (ferr) - return imgtool_floppy_error(ferr); - - if (flags) - return IMGTOOLERR_READERROR; - } - else - { - err = rt11_get_sector_position(image, block, head, track, sector); - if (err) - return err; - - ferr = floppy_read_indexed_sector(imgtool_floppy(image), head, track, sector, 0, buffer, BLOCK_SIZE); - if (ferr) - return imgtool_floppy_error(ferr); - - ferr = floppy_get_indexed_sector_info(imgtool_floppy(image), head, track, sector, NULL, NULL, NULL, NULL, &flags); - if (ferr) - return imgtool_floppy_error(ferr); - - if (flags) - return IMGTOOLERR_READERROR; - } - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t rt11_probe_geometry(imgtool::image &image) -{ - floperr_t ferr; - rt11_diskinfo *di = get_rt11_info(image); - - // MX (11x256 byte sectors) or MY (10x512 byte sectors)? - ferr = floppy_get_indexed_sector_info(imgtool_floppy(image), 0, 0, 0, NULL, NULL, NULL, &di->sector_size, NULL); - if (ferr) - return imgtool_floppy_error(ferr); - - if (di->sector_size == 256) - di->sectors = 11; - else - di->sectors = 10; - - // double- or single-sided? - ferr = floppy_get_indexed_sector_info(imgtool_floppy(image), 1, 0, 0, NULL, NULL, NULL, NULL, NULL); - if (ferr) - di->heads = 1; - else - di->heads = 2; - - // 80 or 40 tracks? - ferr = floppy_get_indexed_sector_info(imgtool_floppy(image), 0, 50, 0, NULL, NULL, NULL, NULL, NULL); - if (ferr) - di->tracks = 40; - else - di->tracks = 80; - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t rt11_image_open(imgtool::image &image, imgtool::stream::ptr &&dummy) -{ - imgtoolerr_t err; - uint8_t buffer[BLOCK_SIZE]; - rt11_diskinfo *di = get_rt11_info(image); - - di->cached_head = -1; - di->cached_track = -1; - memset(di->map, -1, sizeof(di->map)); - // dummy values for rt11_image_readblock - di->tracks = 40; - di->heads = 1; - - err = rt11_probe_geometry(image); - if (err) - return err; - - /* load home block */ - err = rt11_image_readblock(image, buffer, HOME_BLOCK); - if (err) - return err; - - di->directory_start = pick_integer_le(buffer, 0724, 2); - - // 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); - for (int i = 0; i < 510; i+=2) - { - tmp += pick_integer_le(buffer, i, 2); - } - - /* sanity check these values */ - if (cksum != tmp) - { - fprintf(stderr, "cksum stored:computed %04x:%04x\n", cksum, tmp); - return IMGTOOLERR_CORRUPTIMAGE; - } -#endif - if (di->directory_start != 6) - { - return IMGTOOLERR_CORRUPTIMAGE; - } - - /* load first directory segment */ - err = rt11_image_readblock(image, buffer, di->directory_start); - 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->dirents_per_block = (2 * BLOCK_SIZE - 10) / di->dirent_size; - - return IMGTOOLERR_SUCCESS; -} - -static void rt11_image_info(imgtool::image &image, std::ostream &stream) -{ - uint8_t buffer[BLOCK_SIZE]; - char system[4]; - char vid[13], oid[13], sid[13]; - - rt11_image_readblock(image, buffer, HOME_BLOCK); - rt11_from_rad50(system, (uint16_t *)&buffer[0726], 1); - system[3] = '\0'; - - memcpy(vid, &buffer[0730], 12); - memcpy(oid, &buffer[0744], 12); - memcpy(sid, &buffer[0760], 12); - vid[12] = '\0'; - oid[12] = '\0'; - sid[12] = '\0'; - - stream << "System version: '" << system << "', System ID: '" << sid << "', Volume ID: '" << vid << "', Owner: '" << oid << "'"; -} - -// directory operations - -static imgtoolerr_t rt11_enum_seek(imgtool::image &image, - rt11_direnum *rt11enum, uint16_t segment, uint16_t index) -{ - const rt11_diskinfo *di = get_rt11_info(image); - imgtoolerr_t err; - uint8_t buffer[BLOCK_SIZE]; - - if (rt11enum->segment != segment) - { - if (segment != 0) - { - err = rt11_image_readblock(image, buffer, di->directory_start + (segment - 1) * 2); - if (err) - return err; - memcpy(rt11enum->segment_data, buffer, sizeof(buffer)); - - err = rt11_image_readblock(image, buffer, di->directory_start + (segment - 1) * 2 + 1); - if (err) - return err; - memcpy(&rt11enum->segment_data[BLOCK_SIZE], buffer, sizeof(buffer)); - - rt11enum->data = pick_integer_le(rt11enum->segment_data, 8, 2); - } - rt11enum->segment = segment; - } - - rt11enum->index = index; - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t rt11_get_next_dirent(imgtool::image &image, - rt11_direnum *rt11enum, rt11_dirent &rt_ent) -{ - imgtoolerr_t err; - const rt11_diskinfo *di = get_rt11_info(image); - uint32_t next_segment, next_index; - uint32_t offset; - - memset(&rt_ent, 0, sizeof(rt_ent)); - - /* have we hit the end of the file? */ - if (rt11enum->segment == 0) - return IMGTOOLERR_SUCCESS; - - /* populate the resulting dirent */ - offset = (rt11enum->index * di->dirent_size) + 10; - rt_ent.status = pick_integer_le(rt11enum->segment_data, offset, 2); - 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.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); - - /* 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_index = 0; - } - - if (next_segment > di->total_segments || next_segment > di->last_segment) - return IMGTOOLERR_CORRUPTIMAGE; - - /* seek next segment */ - err = rt11_enum_seek(image, rt11enum, next_segment, next_index); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t rt11_image_beginenum(imgtool::directory &enumeration, const char *path) -{ - imgtoolerr_t err; - imgtool::image &image(enumeration.image()); - - /* seek initial block */ - err = rt11_enum_seek(image, (rt11_direnum *) enumeration.extra_bytes(), 1, 0); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t rt11_image_nextenum(imgtool::directory &enumeration, imgtool_dirent &ent) -{ - imgtoolerr_t err; - imgtool::image &image(enumeration.image()); - rt11_direnum *rt11enum = (rt11_direnum *)enumeration.extra_bytes(); - rt11_dirent rt_ent; - - do - { - err = rt11_get_next_dirent(image, rt11enum, rt_ent); - if (err) - return err; - } - while (rt11enum->segment && !is_file_storagetype(rt_ent.status)); - - /* end of file? */ - if (rt11enum->segment == 0) - { - ent.eof = 1; - return IMGTOOLERR_SUCCESS; - } - - ent.directory = 0; - ent.lastmodified_time = rt11_crack_time(rt_ent.time); - ent.filesize = rt_ent.filesize; - - rt11_filename_from_rad50(ent.filename, rt_ent.filename); - - snprintf(ent.attr, sizeof(ent.attr), "%c%c%c %4d %06o", - rt_ent.status & E_PROT ? 'P' : '.', - rt_ent.time == 0 ? 'B' : '.', - rt_ent.status & E_TENT ? 'T' : '.', - rt_ent.data, rt_ent.status); - - return IMGTOOLERR_SUCCESS; -} - -// file operations - -static imgtoolerr_t rt11_lookup_path(imgtool::image &image, const char *path, - creation_policy_t create, rt11_direnum *direnum, rt11_dirent *rt_ent) -{ - imgtoolerr_t err; - - rt11_direnum my_direnum; - if (!direnum) - direnum = &my_direnum; - - memset(direnum, 0, sizeof(*direnum)); - err = rt11_enum_seek(image, direnum, 1, 0); - if (err) - return err; - - uint16_t this_segment; - uint32_t this_index; - char filename[16]; - do - { - this_segment = direnum->segment; - this_index = direnum->index; - - err = rt11_get_next_dirent(image, direnum, *rt_ent); - if (err) - return err; - rt11_filename_from_rad50(filename, rt_ent->filename); - } - while(direnum->segment && (strcmp(path, filename) || - !is_file_storagetype(rt_ent->status))); - - if (!direnum->segment) - { - /* did not find file; maybe we need to create it */ - if (create == CREATE_NONE) - return IMGTOOLERR_FILENOTFOUND; - } - else - { - /* we've found the file; seek that dirent */ - err = rt11_enum_seek(image, direnum, this_segment, this_index); - if (err) - return err; - } - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t rt11_read_bootblock(imgtool::partition &partition, imgtool::stream &stream) -{ - imgtoolerr_t err; - uint8_t block[BLOCK_SIZE]; - - err = rt11_image_readblock(partition.image(), block, 0); - if (err) - return err; - - stream.write(block, sizeof(block)); - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t rt11_image_readfile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &destf) -{ - imgtoolerr_t err; - imgtool::image &image(partition.image()); - rt11_dirent rt_ent; - uint8_t buffer[BLOCK_SIZE]; - - if (filename == FILENAME_BOOTBLOCK) - return rt11_read_bootblock(partition, destf); - - err = rt11_lookup_path(image, filename, CREATE_NONE, NULL, &rt_ent); - if (err) - return err; - - for (uint16_t i = rt_ent.data; i < rt_ent.data + (rt_ent.filesize / BLOCK_SIZE); i++) - { - err = rt11_image_readblock(image, buffer, i); - if (err) - return err; - - destf.write(buffer, BLOCK_SIZE); - } - - return IMGTOOLERR_SUCCESS; -} - - -void rt11_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_OPEN_IS_STRICT: info->i = 1; break; - case IMGTOOLINFO_INT_SUPPORTS_LASTMODIFIED_TIME: info->i = 1; break; - case IMGTOOLINFO_INT_SUPPORTS_BOOTBLOCK: info->i = 1; break; - case IMGTOOLINFO_INT_BLOCK_SIZE: info->i = BLOCK_SIZE; break; - case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES: info->i = sizeof(rt11_diskinfo); break; - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(rt11_direnum); break; - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "rt11"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "RT11 format"); break; - case IMGTOOLINFO_STR_FILE: strcpy(info->s = imgtool_temp_str(), __FILE__); break; - case IMGTOOLINFO_STR_EOLN: strcpy(info->s = imgtool_temp_str(), EOLN_CRLF); break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case IMGTOOLINFO_PTR_INFO: info->info = rt11_image_info; break; - case IMGTOOLINFO_PTR_MAKE_CLASS: info->make_class = imgtool_floppy_make_class; break; - case IMGTOOLINFO_PTR_GET_GEOMETRY: info->get_geometry = rt11_image_get_geometry; break; - case IMGTOOLINFO_PTR_READ_BLOCK: info->read_block = rt11_image_readblock; break; - case IMGTOOLINFO_PTR_BEGIN_ENUM: info->begin_enum = rt11_image_beginenum; break; - case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = rt11_image_nextenum; break; - case IMGTOOLINFO_PTR_READ_FILE: info->read_file = rt11_image_readfile; break; - - case IMGTOOLINFO_PTR_FLOPPY_OPEN: info->open = rt11_image_open; break; - case IMGTOOLINFO_PTR_FLOPPY_FORMAT: info->p = (void *) floppyoptions_default; break; - } -} diff --git a/src/tools/imgtool/modules/thomson.cpp b/src/tools/imgtool/modules/thomson.cpp deleted file mode 100644 index be584bd..0000000 --- a/src/tools/imgtool/modules/thomson.cpp +++ /dev/null @@ -1,2073 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Antoine Mine -/**************************************************************************** - - Copyright (C) Antoine Mine' 2006 - - Thomson 8-bit micro-computers. - - Handles SAP, QD and FD floppy formats with a BASIC-DOS filesystem - (most floppies except some games and demo). - -*****************************************************************************/ - -/* TODO: - - improve two-sided floppy support - - check & correct BASIC read filter - - implement BASIC write filter - - handle accented letters - */ - - -/* Thomson floppy geometry are: - - 5"1/4 single density: 40 tracks, 16 sectors/track, 128 bytes/sector - - 5"1/4 double density: 40 tracks, 16 sectors/track, 256 bytes/sector - - 3"1/2 double density: 80 tracks, 16 sectors/track, 256 bytes/sector - - 2"8: 25 logical tracks, 16 logical sectors/track, 128 bytes/sector - - Notes: - - - 2"8 QDD actually contain a single spiraling track, with 400 128-byte - sectors; however, the filesystem considers it has 25 virtual tracks of - 16 sectors => we do the same in imgtool (but thomflop.c uses a 400-sector - addressing to emulate the device hardware) - - - tracks always have 16 sectors, this is requred by the filesystem - - - two-sided floppies are handled as two one-sided floppies in two - logical floppy drives on the original Thomsons; each has its own - independent FAT and directory. - In imgtool, we handle two-sided images as two partitions. - For now, only 3"1/2 .fd and QDD .qd files can be two-sided. - - - it seems possible to create 3"1/2 single density floppies on the TO9, - I am not sure this is standard, and we do not support it... - -*/ - - -/* Microsoft BASIC Filesystem. - - The floppy is divided into blocks, with always two blocks / track. - Also, in double density, only the first 255 bytes of each 256-byte - sector is used. Thus, blocks are 1024 bytes in single density, and - 2040 bytes in double density. - Depending on the number of tracks, there can be 50, 80 or 160 blocks. - - Filesystem data always occupy track 20, whatever the floppy geometry. - - * sector 1: - - bytes 0-7: floppy name - - remaining bytes: undocumented, seem unused - - * sector 2: FAT, 1 byte info per block - - byte 0: always 0 - - byte 1: block 0 - ... - - byte i: block i-1 - ... - - byte 160: block 159 - - remaining bytes: undocumented, seem unused - - The byte has the following meaning: - - ff: block is free - - fb: block is reserved - - 00-bf: block allocated, points to then next file block - - c1-c8: last block in file, (value & 15) is the number of sectors - actually allocated to the file - - Note: in single density, we can reference only 127 blocks. This is not - a problem because single density floppies can only have 50 or 80 blocks, - never 160. - - * sector 3-16: directory - - no subdirectories - - each file entry occupies 32 bytes: - - bytes 00-07: filename, padded with whitespaces - - bytes 08-0A: file extension, padedd with whitespaces - - byte 0B: file type - . 0 = BASIC, ASCII or binary program (B) - . 1 = BASIC or ASCII data (D) - . 2 = machine code (M) - . 3 = ASCII assembler file (A) - - byte 0C: format flag - . 00 = binary (tokenized) - . ff = ASCII - - byte 0D: first block - - bytes 0E-0F: bytes used in the last sector - - bytes 10-17: comment - - byte 18: day (of month) - - byte 19: month - - byte 1A: year (two last digits) - - bytes 1B-1f: unknown - - Note that byte 0 has a special significance: - - 00: free directory entry - - 20-7F: actual directory entry, value is the first character ini filename - - ff: end of directory - - There can be 56 files in single density, 112 in double density. - */ - -#include "imgtool.h" -#include "filter.h" -#include "iflopimg.h" - -#include "formats/imageutl.h" -#include "corestr.h" -#include "opresolv.h" - -#include -#include - - -#define MAXSIZE 80*16*256*2 /* room for two faces, double-density, 80 tracks */ - -struct thom_floppy { - imgtool::stream *stream; - - uint16_t sector_size; /* 128 or 256 */ - uint16_t sectuse_size; /* bytes used in sector: 128 or 255 */ - uint8_t tracks; /* 25, 40, or 80 */ - uint8_t heads; /* 1 or 2 */ - uint8_t data[MAXSIZE]; /* image data */ - - int modified; /* data need to be copied back to image file */ - -}; - - -enum thom_dirent_type { - THOM_DIRENT_END, - THOM_DIRENT_FREE, - THOM_DIRENT_FILE, - THOM_DIRENT_INVALID, - -}; - - -struct thom_dirent { - thom_dirent_type type; - int index; - - char name[9]; - char ext[4]; - char comment[9]; - uint8_t ftype; - uint8_t format; - uint8_t firstblock; - uint16_t lastsectsize; - uint8_t day; - uint8_t month; - uint8_t year; - -}; - - -static void thom_basic_get_info(const imgtool_class *clas, uint32_t param, - union imgtoolinfo *info); - -static uint8_t* thom_get_sector(thom_floppy* f, unsigned head, - unsigned track, unsigned sector); - - -static thom_floppy *get_thom_floppy(imgtool::image &image) -{ - return (thom_floppy*)image.extra_bytes(); -} - -/*********************** .fd / .qd format ************************/ - -/* .fd and .qd formats are very simple: the sectors are simply put one after - another, starting at sector 1 of track 0 to sector 16 track 0, then - starting again at sector 1 of track 1, and so on. - There is no image or sector header, and no gap between sectors. - The number of tracks and sector size are determined by the extension - (.fd have 40 or 80 tracks, .qd have 25 tracks) and the file size. -*/ - -static imgtoolerr_t thom_open_fd_qd(imgtool::image &img, imgtool::stream::ptr &&stream) -{ - thom_floppy* f = get_thom_floppy(img); - int size = stream->size(); - - f->stream = stream.get(); - f->modified = 0; - - /* guess format */ - switch ( size ) { - case 81920: - f->tracks = 40; - f->sector_size = 128; - f->sectuse_size = 128; - f->heads = 1; - break; - - case 163840: - f->tracks = 40; - f->sector_size = 256; - f->sectuse_size = 255; - f->heads = 1; - /* could also be: sector_size=128, heads=2 */ - /* maight even be: tracks=80, sector_size=128 */ - break; - - case 327680: - f->tracks = 80; - f->sector_size = 256; - f->sectuse_size = 255; - f->heads = 1; - /* could also be: tracks=40, heads=2 */ - break; - - case 655360: - f->tracks = 80; - f->sector_size = 256; - f->sectuse_size = 255; - f->heads = 2; - break; - - case 51200: - f->tracks = 25; - f->sector_size = 128; - f->sectuse_size = 128; - f->heads = 1; - break; - - case 62400: - f->tracks = 25; - f->sector_size = 128; - f->sectuse_size = 128; - f->heads = 2; - break; - - default: - return IMGTOOLERR_CORRUPTIMAGE; - } - - assert( size == f->heads * f->tracks * 16 * f->sector_size ); - - f->stream->seek(0, SEEK_SET); - if (f->stream->read(f->data, size ) < size) - return IMGTOOLERR_READERROR; - - f->stream = stream.release(); - return IMGTOOLERR_SUCCESS; -} - -static void thom_close_fd_qd(imgtool::image &img) -{ - thom_floppy* f = get_thom_floppy(img); - - /* save image */ - if ( f->modified ) { - int size = f->heads * f->tracks * 16 * f->sector_size; - f->stream->seek(0, SEEK_SET); - if (f->stream->write(f->data, size) < size) - { - /* logerror( "thom_diskimage_close_fd_qd: write error\n" ); */ - } - } - - delete f->stream; -} - - -/*********************** .sap format ************************/ - -/* SAP format, Copyright 1998 by Alexandre Pukall - - image is composed of: - - byte 0: version (0 or 1) - - bytes 1..65: signature - - bytes 66..end: sectors - - each sector is composed of - - a 4-byte header: - . byte 0: format - 0 3"1/2 double density - 1 5"1/4 low density - . byte 1: protection (?) - . byte 2: track index, in 0..79 - . byte 3: sector index, in 1..16 - - sector data, XOR 0xB3 - - 2-byte CRC of header + data, high byte first - - there is no provision for two-sided images in sap - */ - -static const int sap_magic_num = 0xB3; /* simple XOR crypt */ - -static const char sap_header[]= - "\001SYSTEME D'ARCHIVAGE PUKALL S.A.P. " - "(c) Alexandre PUKALL Avril 1998"; - -static const uint16_t sap_crc[] = { - 0x0000, 0x1081, 0x2102, 0x3183, 0x4204, 0x5285, 0x6306, 0x7387, - 0x8408, 0x9489, 0xa50a, 0xb58b, 0xc60c, 0xd68d, 0xe70e, 0xf78f, -}; - -static uint16_t thom_sap_crc( uint8_t* data, int size ) -{ - int i; - uint16_t crc = 0xffff, crc2; - for ( i = 0; i < size; i++ ) { - crc2 = ( crc >> 4 ) ^ sap_crc[ ( crc ^ data[i] ) & 15 ]; - crc = ( crc2 >> 4 ) ^ sap_crc[ ( crc2 ^ (data[i] >> 4) ) & 15 ]; - } - return crc; -} - -static imgtoolerr_t thom_open_sap(imgtool::image &img, imgtool::stream::ptr &&stream) -{ - thom_floppy* f = get_thom_floppy(img); - uint8_t buf[262]; - - f->stream = stream.get(); - f->modified = 0; - - // check image header - f->stream->seek(0, SEEK_SET); - f->stream->read(buf, 66 ); - if ( memcmp( buf+1, sap_header+1, 65 ) ) return IMGTOOLERR_CORRUPTIMAGE; - - /* guess format */ - f->stream->read(buf, 1 ); - switch ( buf[0] ) - { - case 1: - case 3: - f->heads = 1; - f->tracks = 40; - f->sector_size = 128; - f->sectuse_size = 128; - break; - case 0: - case 2: - case 4: - f->heads = 1; - f->tracks = 80; - f->sector_size = 256; - f->sectuse_size = 255; - break; - default: - return IMGTOOLERR_CORRUPTIMAGE; - } - - f->stream->seek(66, SEEK_SET); - while ( 1) { - int i, sector, track; - uint16_t crc; - - /* load sector */ - if (f->stream->read(buf, 6 + f->sector_size ) < 6 + f->sector_size ) - break; - - /* parse sector header */ - track = buf[2]; - sector = buf[3]; - if ( sector < 1 || sector > 16 || track >= f->tracks ) - return IMGTOOLERR_CORRUPTIMAGE; - - /* decrypt */ - for ( i = 0; i < f->sector_size; i++ ) buf[ i + 4 ] ^= sap_magic_num; - memcpy( thom_get_sector( f, 0, track, sector ), buf + 4, f->sector_size ); - - /* check CRC */ - crc = thom_sap_crc( buf, f->sector_size + 4 ); - if ( ( (crc >> 8) != buf[ f->sector_size + 4 ] ) || - ( (crc & 0xff) != buf[ f->sector_size + 5 ] ) ) - return IMGTOOLERR_CORRUPTIMAGE; - } - - f->stream = stream.release(); - return IMGTOOLERR_SUCCESS; -} - -static void thom_close_sap(imgtool::image &img) -{ - thom_floppy* f = get_thom_floppy(img); - - if ( f->modified ) { - int i, sector, track; - uint8_t buf[262]; - uint16_t crc; - - /* rewind */ - f->stream->seek(0, SEEK_SET); - - /* image header */ - if ( f->stream->write(sap_header, 66) < 66) { - /* logerror( "thom_diskimage_close_sap: write error\n" ); */ - return; - } - - for ( track = 0; track < f->tracks; track++ ) - for ( sector = 1; sector <= 16; sector++ ) { - /* sector header & data */ - buf[0] = ( f->tracks == 80 ) ? 2 : 1; - buf[1] = 0; - buf[2] = track; - buf[3] = sector; - memcpy( buf + 4, - thom_get_sector( f, 0, track, sector), f->sector_size ); - - /* compute crc */ - crc = thom_sap_crc( buf, f->sector_size + 4 ); - buf[ f->sector_size + 4 ] = crc >> 8; - buf[ f->sector_size + 5 ] = crc & 0xff; - - /* crypt */ - for ( i = 0; i < f->sector_size; i++ ) buf[ i + 4 ] ^= sap_magic_num; - - /* save */ - if (f->stream->write(buf, f->sector_size + 6) < - f->sector_size + 6) { - /* logerror( "thom_diskimage_close_sap: write error\n" ); */ - return; - } - } - } - - delete f->stream; -} - - -/*********************** low-level functions *********************/ - -static uint8_t* thom_get_sector(thom_floppy* f, unsigned head, - unsigned track, unsigned sector) -{ - assert( head < f->heads); - assert( track < f->tracks ); - assert( sector > 0 && sector <= 16 ); - return & f->data[ ( (head * f->tracks + track) * 16 + (sector-1) ) * - f->sector_size ]; -} - -static int thom_nb_blocks(thom_floppy* f) -{ - int n1 = f->tracks * 2; /* 2 blocks per track */ - int n2 = f->sector_size - 1; /* FAT entries */ - return (n1 < n2) ? n1 : n2; -} - -static int thom_max_dirent(thom_floppy* f) -{ - return 14 * f->sector_size / 32; -} - -/* remove trailing spaces */ -static void thom_stringify(char* str) -{ - char* s = str + strlen(str) - 1; - while ( s >= str && *s == ' ' ) { *s = 0; s--; } - for ( s = str; *s; s++ ) - if ( (uint8_t)*s == 0xff ) *s = 0; - else if ( *s < ' ' || *s >= 127 ) *s = '?'; -} - -/* pad with spaces until the length is nb */ -static void thom_unstringity(char* str, int nb) -{ - char* s = str; - while ( s < str + nb && *s ) s++; - while ( s < str + nb ) { *s = ' '; s++; } -} - -/* get filename and extension & truncate them to 8 + 3 */ -static void thom_conv_filename(const char* s, char name[9], char ext[4]) -{ - int i; - memset( name, 0, 9 ); - memset( ext, 0, 4 ); - for ( i = 0; i < 8 && *s && *s != '.'; i++, s++ ) name[i] = *s; - while ( *s && *s != '.' ) s++; - if ( *s == '.' ) { - s++; - for ( i = 0; i < 3 && *s; i++, s++ ) ext[i] = *s; - } -} - -static imgtool::datetime thom_crack_time(thom_dirent* d) -{ - /* check */ - if ( d->day < 1 || d->day > 31 || d->month < 1 || d->month > 12 ) return imgtool::datetime(); - - /* converts */ - util::arbitrary_datetime dt; - dt.second = 0; - dt.minute = 0; - dt.hour = 0; - dt.day_of_month = d->day; - dt.month = d->month; - dt.year = d->year + (d->year < 65 ? 2000 : 1900); - return imgtool::datetime(imgtool::datetime::datetime_type::LOCAL, dt); -} - -static void thom_make_time(thom_dirent* d, time_t time) -{ - if ( ! time ) { - d->day = d->month = d->year = 0; - } - else { - struct tm t = *localtime( &time ); - d->day = t.tm_mday; - d->month = t.tm_mon + 1; - d->year = t.tm_year % 100; - } -} - -static void thom_make_time_now(thom_dirent* d) -{ - time_t now; - time( &now ); - thom_make_time( d, now ); -} - -static void thom_get_dirent(thom_floppy* f, unsigned head, - unsigned n, thom_dirent* d) -{ - uint8_t* base = thom_get_sector( f, head, 20, 3 ) + n * 32; - memset( d, 0, sizeof(*d) ); - d->index = n; - if ( n >= thom_max_dirent( f ) ) - d->type = THOM_DIRENT_END; - else if ( *base == 0xff ) - d->type = THOM_DIRENT_END; - else if ( *base == 0 ) - d->type = THOM_DIRENT_FREE; - else { - int i; - /* fill regular entry */ - d->type = THOM_DIRENT_FILE; - memcpy( d->name, base, 8 ); - memcpy( d->ext, base + 8, 3 ); - memcpy( d->comment, base + 16, 8 ); - thom_stringify( d->name ); - thom_stringify( d->ext ); - thom_stringify( d->comment ); - d->ftype = base[11]; - d->format = base[12]; - d->firstblock = base[13]; - d->lastsectsize = ((int)base[14] << 8) + base[15]; - d->day = base[24]; - d->month = base[25]; - d->year = base[26]; - /* sanity check */ - for ( i = 0; i < 11; i++ ) - if ( base[i] < ' ' || base[i] > 127 ) d->type = THOM_DIRENT_INVALID; - } -} - -static void thom_set_dirent(thom_floppy* f, unsigned head, - unsigned n, thom_dirent* d) -{ - uint8_t* base = thom_get_sector( f, head, 20, 3 ) + n * 32; - if ( n >= thom_max_dirent( f ) ) return; - memset( base, 0, 32 ); - if ( d->type == THOM_DIRENT_END ) base[ 0 ] = 0xff; - else if ( d->type == THOM_DIRENT_FREE ) base[ 0 ] = 0; - else { - memcpy( base, d->name, 8 ); - memcpy( base + 8, d->ext, 3 ); - memcpy( base + 16, d->comment, 8 ); - thom_unstringity( (char*)base, 8 ); - thom_unstringity( (char*)base + 8, 3 ); - if ( base[16] ) thom_unstringity( (char*)base + 16, 8 ); - base[11] = d->ftype; - base[12] = d->format; - base[13] = d->firstblock; - base[14] = d->lastsectsize >> 8; - base[15] = d->lastsectsize & 0xff; - base[24] = d->day; - base[25] = d->month; - base[26] = d->year; - } - f->modified = 1; -} - -/* returns 1 if file found, 0 if not */ -static int thom_find_dirent(thom_floppy* f, unsigned head, - const char* name, thom_dirent* d) -{ - 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++; - } -} - -/* returns 1 if free entry found, 0 if none available */ -static int thom_find_free_dirent(thom_floppy* f, unsigned head, thom_dirent* d) -{ - int n = 0; - while ( 1 ) { - thom_get_dirent( f, head, n, d ); - if ( d->type == THOM_DIRENT_FREE ) return 1; - if ( d->type == THOM_DIRENT_END ) break; - n++; - } - if ( n + 1 >= thom_max_dirent( f ) ) return 0; - thom_set_dirent( f, head, n+1, d ); - d->type = THOM_DIRENT_FREE; - return 1; -} - -/* returns the file size in bytes, or -1 if error */ -static int thom_get_file_size(thom_floppy* f, unsigned head, thom_dirent* d) -{ - uint8_t* fat = thom_get_sector( f, head, 20, 2 ); - int nbblocks = thom_nb_blocks(f); - int block = d->firstblock; - int size = 0; - int timeout = nbblocks; - if ( d->type != THOM_DIRENT_FILE ) return -1; - if ( block >= nbblocks ) return -1; - block = fat[ block + 1 ]; - while ( 1 ) { - if ( block < nbblocks ) { - /* full block */ - size += 8 * f->sectuse_size; - block = fat[ block + 1 ]; - } - else if ( block >= 0xc1 && block <= 0xc8 ) { - /* last block in file */ - size += (block-0xc1) * f->sectuse_size; - size += d->lastsectsize; - return size; - } - else return -1; - timeout--; - if ( timeout < 0 ) return -1; - } -} - -/* number of blocks used by file */ -static int thom_get_file_blocks(thom_floppy* f, unsigned head, thom_dirent* d) -{ - uint8_t* fat = thom_get_sector( f, head, 20, 2 ); - int nbblocks = thom_nb_blocks(f); - int block = d->firstblock; - int nb = 0; - if ( d->type != THOM_DIRENT_FILE ) return 0; - if ( block >= nbblocks ) return 0; - block = fat[ block + 1 ]; - while ( 1 ) { - if ( block < nbblocks ) { - /* full block */ - nb++; - block = fat[ block + 1 ]; - } - else if ( block >= 0xc1 && block <= 0xc8 ) { - /* last block in file */ - nb++; - return nb; - } - else return nb; - } -} - -/* number of free blocks */ -static int thom_get_free_blocks(thom_floppy* f, unsigned head) -{ - uint8_t* fat = thom_get_sector( f, head, 20, 2 ); - int nbblocks = thom_nb_blocks(f); - int i, nb = 0; - for ( i = 1; i <= nbblocks; i++ ) - if ( fat[i] == 0xff ) nb++; - return nb; -} - -/* dump file contents into dst */ -static void thom_get_file(thom_floppy* f, unsigned head, - thom_dirent* d, imgtool::stream &dst) -{ - uint8_t* fat = thom_get_sector( f, head, 20, 2 ); - int nbblocks = thom_nb_blocks(f); - int block = d->firstblock; - if ( block >= nbblocks ) return; - while ( 1 ) - { - int nextblock = fat[ block + 1 ]; - int track = block / 2; - int firstsect = (block % 2) ? 9 : 1; - if ( nextblock < nbblocks ) - { - /* full block */ - int i; - for ( i = 0; i < 8; i++ ) - { - uint8_t* data = thom_get_sector( f, head, track, firstsect + i ); - dst.write(data, f->sectuse_size); - } - block = fat[ block + 1 ]; - } - else if ( nextblock >= 0xc1 && nextblock <= 0xc8 ) - { - /* last block in file */ - int i; - uint8_t* data; - for ( i = 0; i < nextblock - 0xc1; i++ ) - { - data = thom_get_sector( f, head, track, firstsect + i ); - dst.write(data, f->sectuse_size); - } - data = thom_get_sector( f, head, track, firstsect + i ); - dst.write(data, d->lastsectsize); - return; - } - else - { - /* invalid, assume last block */ - uint8_t* data = thom_get_sector( f, head, track, firstsect ); - dst.write(data, d->lastsectsize); - return; - } - block = nextblock; - } -} - -static void thom_del_file(thom_floppy* f, unsigned head, thom_dirent* d) -{ - uint8_t* fat = thom_get_sector( f, head, 20, 2 ); - int nbblocks = thom_nb_blocks(f); - int block = d->firstblock; - if ( d->type != THOM_DIRENT_FILE ) return; - if ( block >= nbblocks ) return; - while ( 1 ) { - int nextblock = fat[ block + 1 ]; - fat[ block ] = 0xff; - if ( nextblock < nbblocks ) block = fat[ block + 1 ]; - else break; - } - d->type = THOM_DIRENT_FREE; - thom_set_dirent( f, head, d->index, d ); - f->modified = 1; -} - -/* create a new file or overwrite an old one, with the contents of src */ -static void thom_put_file(thom_floppy* f, unsigned head, - thom_dirent* d, imgtool::stream &src) -{ - int size = src.size(); - uint8_t* fat = thom_get_sector( f, head, 20, 2 ); - int nbblocks = thom_nb_blocks(f); - int block; - - /* find first free block */ - for ( block = 0; block < nbblocks && fat[ block + 1 ] != 0xff; block++ ); - if ( block >= nbblocks ) return; - d->firstblock = block; - - /* store file */ - while (1) { - int track = block / 2; - int firstsect = (block % 2) ? 9 : 1; - int i; - - /* store data, full sectors */ - for ( i = 0; i < 8 && size > f->sectuse_size; i++ ) { - uint8_t* dst = thom_get_sector( f, head, track, firstsect + i ); - src.read(dst, f->sectuse_size); - size -= f->sectuse_size; - } - - /* store data, last sector */ - if ( i < 8 ) { - uint8_t* dst = thom_get_sector( f, head, track, firstsect + i ); - src.read(dst, size); - fat[ block + 1 ] = 0xc1 + i; - d->lastsectsize = size; - break; - } - - /* find next free block & update fat */ - i = block; - for ( block++; block < nbblocks && fat[ block + 1 ] != 0xff; block++ ); - if ( block >= nbblocks ) { - /* out of memory! */ - fat[ i + 1 ] = 0; - d->lastsectsize = 0; - break; - } - fat[ i + 1 ] = block; - } - - d->type = THOM_DIRENT_FILE; - thom_set_dirent( f, head, d->index, d ); - f->modified = 1; -} - - -/********************** module functions ***********************/ - -static imgtoolerr_t thom_get_geometry(imgtool::image &img, uint32_t* tracks, - uint32_t* heads, uint32_t* sectors) -{ - thom_floppy* f = get_thom_floppy(img); - if ( tracks ) *tracks = f->tracks; - if ( heads ) *heads = f->heads; - if ( sectors ) *sectors = 16; - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t thom_read_sector(imgtool::image &img, uint32_t track, - uint32_t head, uint32_t sector, std::vector &buffer) -{ - thom_floppy* f = get_thom_floppy(img); - if ( head >= f->heads || sector < 1 || sector > 16 || track >= f->tracks ) - return IMGTOOLERR_SEEKERROR; - - // resize the buffer - try { buffer.resize(f->sector_size); } - catch (std::bad_alloc const &) { return IMGTOOLERR_OUTOFMEMORY; } - - memcpy( &buffer[0], thom_get_sector( f, head, track, sector ), f->sector_size); - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t thom_write_sector(imgtool::image &img, uint32_t track, - uint32_t head, uint32_t sector, - const void *buf, size_t len, int ddam) -{ - thom_floppy* f = get_thom_floppy(img); - if ( f->stream->is_read_only() ) return IMGTOOLERR_WRITEERROR; - if ( head >= f->heads || sector < 1 || sector > 16 || track >= f->tracks ) - return IMGTOOLERR_SEEKERROR; - if ( len > f->sector_size) return IMGTOOLERR_WRITEERROR; - f->modified = 1; - memcpy( thom_get_sector( f, head, track, sector ), buf, len ); - return IMGTOOLERR_SUCCESS; -} - -/* returns floopy name */ -/* actually, each side has its own name, but we only return the one on side 0. - */ -static void thom_info(imgtool::image &img, std::ostream &stream) -{ - thom_floppy* f = get_thom_floppy(img); - uint8_t* base = thom_get_sector( f, 0, 20, 1 ); - char buf[9]; - memcpy( buf, base, 8 ); - buf[8] = 0; - thom_stringify( buf ); - stream << buf; -} - -/* each side of a floppy has its own filesystem, we treat them as'partitions' - */ -static imgtoolerr_t thom_list_partitions(imgtool::image &img, std::vector &partitions) -{ - thom_floppy* f = get_thom_floppy(img); - - partitions.emplace_back(thom_basic_get_info, 0, 1); - if (f->heads >= 2) - partitions.emplace_back(thom_basic_get_info, 1, 1); - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t thom_open_partition(imgtool::partition &part, - uint64_t first_block, uint64_t block_count) -{ - imgtool::image &img(part.image()); - thom_floppy* f = get_thom_floppy(img); - if ( first_block >= f->heads ) - return IMGTOOLERR_INVALIDPARTITION; - * ( (int*) part.extra_bytes() ) = first_block; - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t thom_begin_enum(imgtool::directory &enumeration, - const char *path) -{ - int* n = (int*) enumeration.extra_bytes(); - *n = 0; - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t thom_next_enum(imgtool::directory &enumeration, imgtool_dirent &ent) -{ - imgtool::partition &part(enumeration.partition()); - int head = *( (int*) part.extra_bytes() ); - imgtool::image &img(part.image()); - thom_floppy* f = get_thom_floppy(img); - int* n = (int*) enumeration.extra_bytes(); - thom_dirent d; - - do { - thom_get_dirent( f, head, *n, &d ); - (*n) ++; - } - while ( d.type == THOM_DIRENT_FREE ); - if ( d.type == THOM_DIRENT_END ) ent.eof = 1; - else if ( d.type == THOM_DIRENT_INVALID ) { - ent.corrupt = 1; - } - else { - int size; - snprintf( ent.filename, sizeof(ent.filename), "%s.%s", d.name, d.ext ); - snprintf( ent.attr, sizeof(ent.attr), "%c %c %s", - (d.ftype == 0) ? 'B' : (d.ftype == 1) ? 'D' : - (d.ftype == 2) ? 'M' : (d.ftype == 3) ? 'A' : '?', - (d.format == 0) ? 'B' : (d.format == 0xff) ? 'A' : '?', - d.comment ); - ent.creation_time = thom_crack_time( &d ); - size = thom_get_file_size( f, head, &d ); - if ( size >= 0 ) ent.filesize = size; - else { - ent.filesize = 0; - ent.corrupt = 1; - } - } - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t thom_free_space(imgtool::partition &part, uint64_t *size) -{ - int head = *( (int*) part.extra_bytes() ); - imgtool::image &img(part.image()); - thom_floppy* f = get_thom_floppy(img); - int nb = thom_get_free_blocks( f, head ); - (*size) = nb * f->sectuse_size * 8; - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t thom_read_file(imgtool::partition &part, - const char *filename, - const char *fork, - imgtool::stream &destf) -{ - int head = *( (int*) part.extra_bytes() ); - imgtool::image &img(part.image()); - thom_floppy* f = get_thom_floppy(img); - thom_dirent d; - char name[9], ext[4], fname[14]; - int size; - - /* convert filename */ - thom_conv_filename( filename, name, ext ); - sprintf( fname, "%s.%s", name, ext ); - - if ( ! thom_find_dirent( f, head, fname, &d ) ) - return IMGTOOLERR_FILENOTFOUND; - size = thom_get_file_size( f, head, &d ); - if ( size < 0 ) return IMGTOOLERR_CORRUPTFILE; - thom_get_file( f, head, &d, destf ); - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t thom_delete_file(imgtool::partition &part, - const char *filename) -{ - int head = *( (int*) part.extra_bytes() ); - imgtool::image &img(part.image()); - thom_floppy* f = get_thom_floppy(img); - thom_dirent d; - char name[9], ext[4], fname[14]; - - /* convert filename */ - thom_conv_filename( filename, name, ext ); - sprintf( fname, "%s.%s", name, ext ); - - if ( ! thom_find_dirent( f, head, fname, &d ) ) - return IMGTOOLERR_FILENOTFOUND; - /*if ( thom_get_file_size( f, head, &d ) < 0 ) return IMGTOOLERR_CORRUPTFILE;*/ - if ( f->stream->is_read_only() ) return IMGTOOLERR_WRITEERROR; - thom_del_file( f, head, &d ); - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t thom_write_file(imgtool::partition &part, - const char *filename, - const char *fork, - imgtool::stream &sourcef, - util::option_resolution *opts) -{ - int head = *( (int*) part.extra_bytes() ); - imgtool::image &img(part.image()); - thom_floppy* f = get_thom_floppy(img); - thom_dirent d; - int size = sourcef.size(); - int blocks = thom_get_free_blocks( f, head ); - char name[9], ext[4], fname[14]; - int is_new = 1; - - if ( f->stream->is_read_only() ) return IMGTOOLERR_WRITEERROR; - - /* convert filename */ - thom_conv_filename( filename, name, ext ); - sprintf( fname, "%s.%s", name, ext ); - - /* check available space & find dir entry */ - if ( thom_find_dirent( f, head, fname, &d ) ) { - /* file already exists: delete it */ - if ( thom_get_file_size( f, head, &d ) < 0 ) return IMGTOOLERR_CORRUPTFILE; - blocks += thom_get_file_blocks( f, head, &d ); - if ( blocks * 8 * f->sectuse_size < size ) return IMGTOOLERR_NOSPACE; - thom_del_file( f, head, &d ); - is_new = 0; - } - else { - /* new file, need new dir entry */ - if ( blocks * 8 * f->sectuse_size < size ) return IMGTOOLERR_NOSPACE; - if ( ! thom_find_free_dirent( f, head, &d ) ) return IMGTOOLERR_NOSPACE; - thom_make_time_now( &d ); - } - - /* fill-in dir entry */ - memcpy( d.name, name, 9 ); - memcpy( d.ext, ext, 4 ); - - /* file type */ - switch ( opts->lookup_int('T') ) { - case 0: - if ( ! is_new ) break; - if ( ! core_stricmp( ext, "BAS" ) ) d.ftype = 0; - else if ( ! core_stricmp( ext, "BAT" ) ) d.ftype = 0; - else if ( ! core_stricmp( ext, "DAT" ) ) d.ftype = 1; - else if ( ! core_stricmp( ext, "ASC" ) ) d.ftype = 1; - else if ( ! core_stricmp( ext, "BIN" ) ) d.ftype = 2; - else if ( ! core_stricmp( ext, "MAP" ) ) d.ftype = 2; - else if ( ! core_stricmp( ext, "CFG" ) ) d.ftype = 2; - else if ( ! core_stricmp( ext, "ASM" ) ) d.ftype = 3; - else d.ftype = 2; - break; - case 1: d.ftype = 0; break; - case 2: d.ftype = 1; break; - case 3: d.ftype = 2; break; - case 4: d.ftype = 3; break; - } - - /* format flag */ - switch ( opts->lookup_int('F') ) { - case 0: - if ( ! is_new ) break; - if ( ! core_stricmp( ext, "DAT" ) ) d.format = 0xff; - else if ( ! core_stricmp( ext, "ASC" ) ) d.format = 0xff; - else if ( ! core_stricmp( ext, "ASM" ) ) d.format = 0xff; - else d.format = 0; - break; - case 1: d.format = 0; break; - case 2: d.format = 0xff; break; - } - - /* comment */ - char const *const comment = opts->lookup_string('C').c_str(); - if (comment && *comment) - strncpy(d.comment, comment, 8); - - /* write file */ - thom_put_file( f, head, &d, sourcef ); - return IMGTOOLERR_SUCCESS; -} - -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()); - thom_floppy* f = get_thom_floppy(img); - thom_dirent d; - int is_basic = 0; - - 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 ( 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; - } - } - else { - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; - } - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t thom_create(imgtool::image &img, - imgtool::stream::ptr &&stream, - util::option_resolution *opts) -{ - thom_floppy* f = get_thom_floppy(img); - int i; - uint8_t* buf; - const char* name; - - f->stream = stream.get(); - f->modified = 0; - - /* get parameters */ - f->heads = opts->lookup_int('H'); - f->tracks = opts->lookup_int('T'); - name = opts->lookup_string('N').c_str(); - switch ( opts->lookup_int('D') ) { - case 0: f->sector_size = 128; f->sectuse_size = 128; break; - case 1: f->sector_size = 256; f->sectuse_size = 255; break; - default: return IMGTOOLERR_PARAMCORRUPT; - } - - /* sanity checks */ - switch ( f->tracks ) { - case 25: if ( f->sector_size != 128 ) return IMGTOOLERR_PARAMCORRUPT; break; - case 40: break; - case 80: if ( f->sector_size != 256 ) return IMGTOOLERR_PARAMCORRUPT; break; - default: return IMGTOOLERR_PARAMCORRUPT; - } - - memset( f->data, 0xe5, sizeof( f->data ) ); - - for ( i = 0; i < f->heads; i++ ) { - /* disk info */ - buf = thom_get_sector( f, i, 20, 1 ); - memset( buf, 0xff, f->sector_size ); - if ( name ) { - strncpy( (char*)buf, name, 8 ); - thom_unstringity( (char*)buf, 8 ); - } - else memset( buf, ' ', 8 ); - - /* FAT */ - buf = thom_get_sector( f, i, 20, 2 ); - memset( buf, 0, f->sector_size ); - memset( buf + 1, 0xff, thom_nb_blocks( f ) ); - buf[ 41 ] = buf[ 42 ] = 0xfe; /* reserved for FAT */ - - /* (empty) directory */ - buf = thom_get_sector( f, i, 20, 3 ); - memset( buf, 0xff, 14 * f->sector_size ); - } - - f->modified = 1; - - f->stream = stream.release(); - return IMGTOOLERR_SUCCESS; -} - - -/****************** BASIC tokenization *********************/ - -/* character codes >= 128 are reserved for BASIC keywords */ - -static const char *const thombas7[2][128] = { - { /* statements */ - "END", "FOR", "NEXT", "DATA", "DIM", "READ", "LET", "GO", "RUN", "IF", - "RESTORE", "RETURN", "REM", "'", "STOP", "ELSE", "TRON", "TROFF", "DEFSTR", - "DEFINT", "DEFSNG", "DEFDBL", "ON", "WAIT", "ERROR", "RESUME", "AUTO", - "DELETE", "LOCATE", "CLS", "CONSOLE", "PSET", "MOTOR", "SKIP", "EXEC", - "BEEP", "COLOR", "LINE", "BOX", "UNMASK", "ATTRB", "DEF", "POKE", "PRINT", - "CONT", "LIST", "CLEAR", "WHILE", "WHEN", "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", "@", - ">", "=", "<", - /* DOS specific */ - "DSKINI", "DSKO$", "KILL", "NAME", "FIELD", "LSET", "RSET", - "PUT", "GET", "VERIFY", "DEVICE", "DIR", "FILES", "WRITE", "UNLOAD", - "BACKUP", "COPY", "CIRCLE", "PAINT", "DRAW", "RENUM", "SWAP", "DENSITY", - }, - { /* functions: 0xff prefix */ - "SGN", "INT", "ABS", "FRE", "SQR", "LOG", "EXP", "COS", "SIN", - "TAN", "PEEK", "LEN", "STR$", "VAL", "ASC", "CHR$", "EOF", "CINT", "CSNG", - "CDBL", "FIX", "HEX$", "OCT$", "STICK", "STRIG", "GR$", "LEFT$", "RIGHT$", - "MID$", "INSTR", "VARPTR", "RND", "INKEY$", "INPUT", "CSRLIN", "POINT", - "SCREEN", "POS", "PTRIG", - /* DOS specific */ - "DSKL", "CVI", "CVS", "CVD", "MKI$", "MKS$", "MKD$", "LOC", "LOF", - "SPACE$", "STRING$", "DSKI$", - } -}; - -/* 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", - "RESTORE", "RETURN", "REM", "'", "STOP", "ELSE", "TRON", "TROFF", "DEFSTR", - "DEFINT", "DEFSNG", NULL, "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", - "OPEN", "CLOSE", "INPEN", "PEN", "PLAY", "TAB(", "TO", "SUB", "FN", - "SPC(", "USING", "USR", "ERL", "ERR", "OFF", "THEN", "NOT", "STEP", - "+", "-", "*", "/", "^", "AND", "OR", "XOR", "EQV", "IMP", "MOD", "@", - ">", "=", "<", - /* DOS specific */ - "DSKINI", "DSKO$", "KILL", "NAME", "FIELD", "LSET", "RSET", - "PUT", "GET", "VERIFY", "DEVICE", "DIR", "FILES", "WRITE", "UNLOAD", - "BACKUP","COPY", "CIRCLE", "PAINT", "DRAW", "RENUM", "SWAP", "SEARCH", - "DENSITY", - }, - { /* 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$", - "MID$", "INSTR", "VARPTR", "RND", "INKEY$", "INPUT", "CSRLIN", "POINT", - "SCREEN", "POS", "PTRIG", - /* DOS specific */ - "DSKL", "CVI", "CVS", "CVD", "MKI$", "MKS$", "MKD$", "LOC", "LOF", - "SPACE$", "STRING$", "DSKI$", - } -}; - -/* BASIC 128 has many new keywords */ -/* DENSITY is missing on BASIC 512 & BASIC 128 for MO6 but, otherwise, they - have the same tokens -*/ -static const char *const thombas128[2][128] = { - { /* statements */ - "END", "FOR", "NEXT", "DATA", "DIM", "READ", "LET", "GO", "RUN", "IF", - "RESTORE", "RETURN", "REM", "'", "STOP", "ELSE", "TRON", "TROFF", "DEFSTR", - "DEFINT", "DEFSNG", "DEFDBL", "ON", "WAIT", "ERROR", "RESUME", "AUTO", - "DELETE", "LOCATE", "CLS", "CONSOLE", "PSET", "MOTOR", "SKIP", "EXEC", - "BEEP", "COLOR", "LINE", "BOX", "UNMASK", "ATTRB", "DEF", "POKE", "PRINT", - "CONT", "LIST", "CLEAR", "INTERVAL", "KEY", "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", "@", - ">", "=", "<", - "DSKINI", "DSKO$", "KILL", "NAME", "FIELD", "LSET", "RSET", - "PUT", "GET", "VERIFY", "DEVICE", "DIR", "FILES", "WRITE", "UNLOAD", - "BACKUP", "COPY", "CIRCLE", "PAINT", "RESET", "RENUM", "SWAP", "DENSITY", - "WINDOW", "PATTERN", "DO", "LOOP", "EXIT", "INMOUSE", "MOUSE", "CHAINE", - "COMMON", "SEARCH", "FWD", "TURTLE", - }, - { /* functions: 0xff prefix */ - "SGN", "INT", "ABS", "FRE", "SQR", "LOG", "EXP", "COS", "SIN", - "TAN", "PEEK", "LEN", "STR$", "VAL", "ASC", "CHR$", "EOF", "CINT", "CSNG", - "CDBL", "FIX", "HEX$", "OCT$", "STICK", "STRIG", "GR$", "LEFT$", "RIGHT$", - "MID$", "INSTR", "VARPTR", "RND", "INKEY$", "INPUT", "CSRLIN", "POINT", - "SCREEN", "POS", "PTRIG", - "DSKL", "CVI", "CVS", "CVD", "MKI$", "MKS$", "MKD$", "LOC", "LOF", - "SPACE$", "STRING$", "DSKI$", - "FKEY$", "MIN(", "MAX(", "ATN", "CRUNCH$", "MTRIG", "EVAL", "PALETTE", - "BANK", "HEAD", "ROT", "SHOW", "ZOOM", "TRACE", - } -}; - -/* tables for simple XOR encryption sieve */ -static const uint8_t crypt1[11] = { - 0x80, 0x19, 0x56, 0xAA, 0x80, 0x76, 0x22, 0xF1, 0x82, 0x38, 0xAA -}; - -static const uint8_t crypt2[13] = { - 0x86, 0x1E, 0xD7, 0xBA, 0x87, 0x99, 0x26, 0x64, 0x87, 0x23, 0x34, 0x58, 0x86 -}; - -/* decrypt BASIC protected files */ -static void thom_decrypt(imgtool::stream &out, imgtool::stream &in) -{ - int i1 = 11, i2 = 13; - while ( 1 ) - { - uint8_t b; - if ( in.read(&b, 1) < 1 ) break; - b = ( (uint8_t)(b - i2) ^ crypt2[i2-1] ^ crypt1[i1-1] ) + i1; - out.putc(b ); - i1--; i2--; - if ( !i1 ) i1 = 11; - if ( !i2 ) i2 = 13; - } -} - -/* encrypt BASIC protected files */ -static void thom_encrypt(imgtool::stream &out, imgtool::stream &in) -{ - int i1 = 11, i2 = 13; - while ( 1 ) - { - uint8_t b; - if ( in.read(&b, 1) < 1 ) break; - b = ( (uint8_t)(b - i1) ^ crypt2[i2-1] ^ crypt1[i1-1] ) + i2; - out.putc(b ); - i1--; i2--; - if ( !i1 ) i1 = 11; - if ( !i2 ) i2 = 13; - } -} - -static imgtoolerr_t thomcrypt_read_file(imgtool::partition &part, - const char *name, - const char *fork, imgtool::stream &dst) -{ - uint8_t buf[3]; - imgtool::stream::ptr org = imgtool::stream::open_mem(nullptr, 0); - imgtoolerr_t err; - if ( !org ) return IMGTOOLERR_OUTOFMEMORY; - - /* read file */ - err = thom_read_file( part, name, fork, *org ); - if (err) - return err; - - org->seek(0, SEEK_SET); - if ( org->read(buf, 3 ) < 3 || buf[0] != 0xfe ) - { - /* regular file */ - org->seek(0, SEEK_SET); - imgtool::stream::transfer_all( dst, *org ); - } - else - { - /* encrypted file */ - dst.putc( '\xff' ); - dst.write(buf+1, 2); - thom_decrypt( dst, *org ); - } - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t thomcrypt_write_file(imgtool::partition &part, - const char *name, - const char *fork, imgtool::stream &src, - util::option_resolution *opts) -{ - uint8_t buf[3]; - - if ( src.read(buf, 3 ) < 3 || buf[0] == 0xfe ) - { - /* too short or already encrypted file */ - src.seek(0, SEEK_SET); - return thom_write_file( part, name, fork, src, opts ); - } - else - { - /* regular file */ - imgtool::stream::ptr dst = imgtool::stream::open_mem(nullptr, 0); - if ( !dst ) return IMGTOOLERR_OUTOFMEMORY; - dst->putc( '\xfe' ); - dst->write(buf+1, 2); - thom_encrypt( *dst, src ); - dst->seek(0, SEEK_SET); - return thom_write_file( part, name, fork, *dst, opts ); - } -} - -void filter_thomcrypt_getinfo(uint32_t state, union filterinfo *info) -{ - switch(state) { - case FILTINFO_STR_NAME: - info->s = "thomcrypt"; - break; - case FILTINFO_STR_HUMANNAME: - info->s = "Thomson BASIC, Protected file encryption (no tokenization)"; - break; - case FILTINFO_PTR_READFILE: - info->read_file = thomcrypt_read_file; - break; - case FILTINFO_PTR_WRITEFILE: - info->write_file = thomcrypt_write_file; - break; - } -} - -static void -thom_accent_grave(imgtool::stream &dst, - uint8_t c) -{ - switch ( c ) { - case 'a': dst.printf("\xc3\xa0"); break; - case 'e': dst.printf("\xc3\xa8"); break; - case 'i': dst.printf("\xc3\xac"); break; - case 'o': dst.printf("\xc3\xb2"); break; - case 'u': dst.printf("\xc3\xb9"); break; - case 'A': dst.printf("\xc3\x80"); break; - case 'E': dst.printf("\xc3\x88"); break; - case 'I': dst.printf("\xc3\x8c"); break; - case 'O': dst.printf("\xc3\x92"); break; - case 'U': dst.printf("\xc3\x99"); break; - default: break; /* invalid data */ - } -} - -static void -thom_accent_acute(imgtool::stream &dst, - uint8_t c) -{ - switch ( c ) { - case 'a': dst.printf("\xc3\xa1"); break; - case 'e': dst.printf("\xc3\xa9"); break; - case 'i': dst.printf("\xc3\xad"); break; - case 'o': dst.printf("\xc3\xb3"); break; - case 'u': dst.printf("\xc3\xba"); break; - case 'A': dst.printf("\xc3\x81"); break; - case 'E': dst.printf("\xc3\x89"); break; - case 'I': dst.printf("\xc3\x8d"); break; - case 'O': dst.printf("\xc3\x93"); break; - case 'U': dst.printf("\xc3\x9a"); break; - default: break; - } -} - -static void -thom_accent_circ(imgtool::stream &dst, - uint8_t c) -{ - switch ( c ) { - case 'a': dst.printf("\xc3\xa2"); break; - case 'e': dst.printf("\xc3\xaa"); break; - case 'i': dst.printf("\xc3\xae"); break; - case 'o': dst.printf("\xc3\xb4"); break; - case 'u': dst.printf("\xc3\xbb"); break; - case 'A': dst.printf("\xc3\x82"); break; - case 'E': dst.printf("\xc3\x8a"); break; - case 'I': dst.printf("\xc3\x8e"); break; - case 'O': dst.printf("\xc3\x94"); break; - case 'U': dst.printf("\xc3\x9b"); break; - default: break; /* invalid data */ - } -} - -static void -thom_accent_uml(imgtool::stream &dst, - uint8_t c) -{ - switch ( c ) { - case 'a': dst.printf("\xc3\xa4"); break; - case 'e': dst.printf("\xc3\xab"); break; - case 'i': dst.printf("\xc3\xaf"); break; - case 'o': dst.printf("\xc3\xb6"); break; - case 'u': dst.printf("\xc3\xbc"); break; - case 'A': dst.printf("\xc3\x84"); break; - case 'E': dst.printf("\xc3\x8b"); break; - case 'I': dst.printf("\xc3\x8f"); break; - case 'O': dst.printf("\xc3\x96"); break; - case 'U': dst.printf("\xc3\x9c"); break; - default: break; /* invalid data */ - } -} - -static void -thom_accent_cedil(imgtool::stream &dst, - uint8_t c) -{ - switch ( c ) { - case 'c': dst.printf("\xc3\xa7"); break; - case 'C': dst.printf("\xc3\x87"); break; - default: break; /* invalid data */ - } -} - -static void -thom_basic_specialchar(imgtool::stream::ptr &src, - imgtool::stream &dst, - uint8_t c) -{ - uint8_t l; - - /* special characters */ - switch ( c ) { - case '#': dst.printf("\xc2\xa3"); return; /* pound */ - case '$': dst.printf("$"); return; /* dollar */ - case '&': dst.printf("#"); return; /* diesis */ - case ',': dst.printf("\xe2\x86\x90"); return; /* arrow left */ - case '-': dst.printf("\xe2\x86\x91"); return; /* arrow up */ - case '.': dst.printf("\xe2\x86\x92"); return; /* arrow right */ - case '/': dst.printf("\xe2\x86\x93"); return; /* arrow down */ - case '0': dst.printf("\xc2\xb0"); return; /* ° */ - case '1': dst.printf("\xc2\xb1"); return; /* ± */ - case '8': dst.printf("\xc3\xb7"); return; /* ÷ */ - case '<': dst.printf("\xc2\xbc"); return; /* ¼ */ - case '=': dst.printf("\xc2\xbd"); return; /* ½ */ - case '>': dst.printf("\xc2\xbe"); return; /* ¾ */ - case 'j': dst.printf("\xc5\x92"); return; /* Å’ */ - case 'z': dst.printf("\xc5\x93"); return; /* Å“ */ - case '{': dst.printf("\xc3\x9f"); return; /* ß */ - case '\'': dst.printf("\xc2\xa7"); return; /* § */ - case 'A': - case 'B': - case 'C': - case 'H': - case 'K': break; /* accents */ - default: return; /* invalid data */ - } - - if ( src->read(&l, 1 ) < 1 ) return; - - /* accents */ - switch ( c ) { - case 'A': thom_accent_grave(dst, l); return; - case 'B': thom_accent_acute(dst, l); return; - case 'C': thom_accent_circ(dst, l); return; - case 'H': thom_accent_uml(dst, l); return; - case 'K': thom_accent_cedil(dst, l); return; - default: break; - } - - /* invalid data */ -} - -struct { - const char *utf8; - const char *thom; -} special_chars[] = { - { "\xc2\xa3", "\x16" "#" }, /* £ */ - { "$", "\x16" "$" }, - { "#", "\x16" "&" }, - { "\xe2\x86\x90", "\x16" "," }, /* arrow left */ - { "\xe2\x86\x91", "\x16" "-" }, /* arrow up */ - { "\xe2\x86\x92", "\x16" "." }, /* arrow right */ - { "\xe2\x86\x93", "\x16" "/" }, /* arrow down */ - { "\xc2\xb0", "\x16" "0" }, /* ° */ - { "\xc2\xb1", "\x16" "1" }, /* ± */ - { "\xc3\xb7", "\x16" "8" }, /* ÷ */ - { "\xc2\xbc", "\x16" "<" }, /* ¼ */ - { "\xc2\xbd", "\x16" "=" }, /* ½ */ - { "\xc2\xbe", "\x16" ">" }, /* ¾ */ - { "\xc5\x92", "\x16" "j" }, /* Å’ */ - { "\xc5\x93", "\x16" "z" }, /* Å“ */ - { "\xc3\x9f", "\x16" "{" }, /* ß */ - { "\xc2\xa7", "\x16" "'" }, /* § */ - - /* accent grave */ - { "\xc3\xa0", "\x16" "Aa" }, - { "\xc3\xa8", "\x16" "Ae" }, - { "\xc3\xac", "\x16" "Ai" }, - { "\xc3\xb2", "\x16" "Ao" }, - { "\xc3\xb9", "\x16" "Au" }, - { "\xc3\x80", "\x16" "AA" }, - { "\xc3\x88", "\x16" "AE" }, - { "\xc3\x8c", "\x16" "AI" }, - { "\xc3\x92", "\x16" "AO" }, - { "\xc3\x99", "\x16" "AU" }, - - /* accent acute */ - { "\xc3\xa1", "\x16" "Ba" }, - { "\xc3\xa9", "\x16" "Be" }, - { "\xc3\xad", "\x16" "Bi" }, - { "\xc3\xb3", "\x16" "Bo" }, - { "\xc3\xba", "\x16" "Bu" }, - { "\xc3\x81", "\x16" "BA" }, - { "\xc3\x89", "\x16" "BE" }, - { "\xc3\x8d", "\x16" "BI" }, - { "\xc3\x93", "\x16" "BO" }, - { "\xc3\x9a", "\x16" "BU" }, - - /* circumflex */ - { "\xc3\xa2", "\x16" "Ca" }, - { "\xc3\xaa", "\x16" "Ce" }, - { "\xc3\xae", "\x16" "Ci" }, - { "\xc3\xb4", "\x16" "Co" }, - { "\xc3\xbb", "\x16" "Cu" }, - { "\xc3\x82", "\x16" "CA" }, - { "\xc3\x8a", "\x16" "CE" }, - { "\xc3\x8e", "\x16" "CI" }, - { "\xc3\x94", "\x16" "CO" }, - { "\xc3\x9b", "\x16" "CU" }, - - /* umlaut */ - { "\xc3\xa4", "\x16" "Ha" }, - { "\xc3\xab", "\x16" "He" }, - { "\xc3\xaf", "\x16" "Hi" }, - { "\xc3\xb6", "\x16" "Ho" }, - { "\xc3\xbc", "\x16" "Hu" }, - { "\xc3\x84", "\x16" "HA" }, - { "\xc3\x8b", "\x16" "HE" }, - { "\xc3\x8f", "\x16" "HI" }, - { "\xc3\x96", "\x16" "HO" }, - { "\xc3\x9c", "\x16" "HU" }, - - /* cedilla */ - { "\xc3\xa7", "\x16" "Kc" }, - { "\xc3\x87", "\x16" "KC" }, - - { NULL, NULL } -}; - -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++) - { - if (!strncmp(&buf[*pos], special_chars[i].utf8, strlen(special_chars[i].utf8))) - { - *pos += strlen(special_chars[i].utf8); - *thom = special_chars[i].thom; - return true; - } - } - - return false; -} - -/* untokenization automatically decrypt protected files */ -static imgtoolerr_t thom_basic_read_file(imgtool::partition &part, - const char *name, - const char *fork, - imgtool::stream &dst, - const char *const table[2][128]) -{ - imgtool::stream::ptr org = imgtool::stream::open_mem(nullptr, 0); - imgtoolerr_t err; - uint8_t buf[4]; - int i; - - if ( !org ) return IMGTOOLERR_OUTOFMEMORY; - - err = thomcrypt_read_file( part, name, fork, *org ); - if (err) - return err; - - org->seek(3, SEEK_SET); /* skip header */ - - while ( 1 ) - { - int in_str = 0, in_fun = 0; - int linelength, linenum; - - /* line header: line length and line number */ - /* I am not sure this is 100% correct but it works in many cases */ - if ( org->read(buf, 2 ) < 2 ) goto end; - linelength = ((int)buf[0] << 8) + (int)buf[1] - 4; - if ( linelength <= 0 ) goto end; - if ( org->read(buf, 2 ) < 2 ) goto end; - linenum = ((int)buf[0] << 8) + buf[1]; - dst.printf( "%u ", linenum ); - - /* process line */ - for ( i = 0; i < linelength; i++ ) - { - uint8_t c; - if ( org->read(&c, 1 ) < 1 ) break; - if ( c == 0 ) - { - /* Sometimes, linelength seems wrong and we must rely on the fact that - BASIC lines are 0-terminated. - At other times, there are 0 embedded within lines or extra stuff - between the 0 and the following line, and so, we must rely - on linelength to cut the line (!) - */ - if ( linelength > 256 ) break; - } - else if ( c == 0xff && ! in_str ) in_fun = 1; /* function prefix */ - else - { - if ( c >= 0x80 && ! in_str ) - { - /* token */ - const char* token = table[ in_fun ][ c - 0x80 ]; - if ( token ) dst.puts(token ); - else dst.puts("???" ); - } - else if ( c == '\x16' ) - { - uint64_t l; - l = org->tell(); - if ( org->read(&c, 1 ) < 1 ) break; - thom_basic_specialchar(org, dst, c); - i += org->tell() - l; /* update i */ - } - else - { - /* regular character */ - if ( c == '"' ) in_str = 1 - in_str; - dst.putc( c ); /* normal letter */ - } - in_fun = 0; - } - } - dst.putc( '\n' ); - } - end: - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t thom_basic_write_file(imgtool::partition &partition, - const char *filename, - const char *fork, - imgtool::stream &sourcef, - util::option_resolution *opts, - const char *const table[2][128]) -{ - imgtool::stream::ptr mem_stream; - char buf[1024]; - int eof = false; - uint32_t len; - char c; - int i, j, pos, in_quotes; - uint16_t line_number; - uint8_t line_header[4]; - uint8_t file_header[3]; - const char *token; - uint8_t token_shift, token_value; - uint64_t line_header_loc, end_line_loc; - - /* open a memory stream */ - mem_stream = imgtool::stream::open_mem(nullptr, 0); - if (!mem_stream) - return IMGTOOLERR_OUTOFMEMORY; - - /* skip past 3-byte header */ - mem_stream->fill(0x00, 3); - - /* loop until the file is complete */ - while(!eof) - { - /* read a line */ - pos = 0; - while((len = sourcef.read(&c, 1)) > 0) - { - /* break if at end of line */ - if ((c == '\r') || (c == '\n')) - break; - - if (pos <= std::size(buf) - 1) - { - buf[pos++] = c; - } - } - eof = (len == 0); - buf[pos] = '\0'; - - /* ignore lines that don't start with digits */ - if (isdigit(buf[0])) - { - /* start at beginning of line */ - pos = 0; - - /* read line number */ - line_number = 0; - while(isdigit(buf[pos])) - { - line_number *= 10; - line_number += (buf[pos++] - '0'); - } - - /* 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); - - /* emit line header */ - line_header_loc = mem_stream->tell(); - mem_stream->write(line_header, sizeof(line_header)); - - /* skip spaces */ - while(isspace(buf[pos])) - pos++; - - /* when we start out, we are not within quotation marks */ - in_quotes = false; - - /* read until end of line */ - while(buf[pos] != '\0') - { - token = nullptr; - token_shift = 0; - token_value = 0; - - if (buf[pos] == '\"') - { - /* flip quotation status */ - in_quotes = !in_quotes; - } - else if (!in_quotes) - { - for (i = 0; i < 2; i++) - { - bool found = false; - for (j = 0; j < 128; j++) - { - if (table[i][j] == nullptr) - continue; - if (!strncmp(&buf[pos], table[i][j], strlen(table[i][j]))) - { - token = table[i][j]; - token_shift = (i == 0) ? 0x00 : 0xff; - token_value = 0x80 + j; - pos += strlen(token); - found = true; - break; - } - } - if (found) - break; - } - } - - /* did we find a token? */ - if (token != nullptr) - { - /* emit the token */ - if (token_shift != 0) - mem_stream->write(&token_shift, 1); - mem_stream->write(&token_value, 1); - } - else if (thom_basic_is_specialchar(buf, &pos, &token)) - { - /* emit the escaped accent */ - mem_stream->write(token, strlen(token)); - } - else - { - /* no token; emit the byte */ - mem_stream->write(&buf[pos++], 1); - } - } - - /* emit line terminator */ - mem_stream->fill(0x00, 1); - - /* 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); - mem_stream->write(line_header, sizeof(line_header)); - mem_stream->seek(end_line_loc, SEEK_SET); - } - } - - /* emit program terminator */ - mem_stream->fill(0x00, 2); - - /* reset stream */ - 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()); - mem_stream->write(file_header, 3); - mem_stream->seek(0, SEEK_SET); - - /* write actual file */ - return partition.write_file(filename, fork, *mem_stream, opts, nullptr); -} - - -#define FILTER(short,long) \ - static imgtoolerr_t short##_read_file(imgtool::partition &part, \ - const char *name, \ - const char *fork, \ - imgtool::stream &dst) \ - { \ - 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) \ - { \ - return thom_basic_write_file( part, name, fork, src, opts, short ); \ - } \ - void filter_##short##_getinfo(uint32_t state, union filterinfo *info) \ - { \ - switch(state) \ - { \ - case FILTINFO_STR_NAME: \ - info->s = #short; \ - break; \ - case FILTINFO_STR_HUMANNAME: \ - info->s = long; \ - break; \ - case FILTINFO_PTR_READFILE: \ - info->read_file = short##_read_file; \ - break; \ - case FILTINFO_PTR_WRITEFILE: \ - info->write_file = short##_write_file; \ - break; \ - } \ - } - -FILTER( thombas5, - "Thomson MO5 w/ BASIC 1.0, Tokenized Files (auto-decrypt)" ) -FILTER( thombas7, - "Thomson TO7 w/ BASIC 1.0, Tokenized Files (auto-decrypt)" ) -FILTER( thombas128, - "Thomson w/ BASIC 128/512, Tokenized Files (auto-decrypt)" ) - - -/************************* driver ***************************/ - -OPTION_GUIDE_START( thom_createimage_optguide ) - OPTION_INT( 'H', "heads", "Heads" ) - OPTION_INT( 'T', "tracks", "Tracks" ) - OPTION_ENUM_START( 'D', "density", "Density" ) - OPTION_ENUM( 0, "SD", "Single density (128 bytes)" ) - OPTION_ENUM( 1, "DD", "Double density (256 bytes)" ) - OPTION_ENUM_END - OPTION_STRING( 'N', "name", "Floppy name" ) -OPTION_GUIDE_END - -OPTION_GUIDE_START( thom_writefile_optguide ) - OPTION_ENUM_START( 'T', "ftype", "File type" ) - OPTION_ENUM( 0, "auto", "Automatic (by extension)" ) - OPTION_ENUM( 1, "B", "Program" ) - OPTION_ENUM( 2, "D", "Data" ) - OPTION_ENUM( 3, "M", "Machine Code" ) - OPTION_ENUM( 4, "A", "Assembler Source" ) - OPTION_ENUM_END - OPTION_ENUM_START( 'F', "format", "Format flag" ) - OPTION_ENUM( 0, "auto", "Automatic (by extension)" ) - OPTION_ENUM( 1, "B", "Binary, Tokenized BASIC" ) - OPTION_ENUM( 2, "A", "ASCII" ) - OPTION_ENUM_END - OPTION_STRING( 'C', "comment", "Comment" ) -OPTION_GUIDE_END - -static void thom_basic_get_info(const imgtool_class *clas, - uint32_t param, - union imgtoolinfo *info) -{ - switch ( param ) { - case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES: - info->i = sizeof(thom_floppy); break; - case IMGTOOLINFO_INT_PARTITION_EXTRA_BYTES: - info->i = sizeof(int); break; - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: - info->i = sizeof(int); break; - case IMGTOOLINFO_INT_SUPPORTS_CREATION_TIME: - case IMGTOOLINFO_INT_PREFER_UCASE: - info->i = 1; break; - case IMGTOOLINFO_INT_PATH_SEPARATOR: - info->i = 0; break; - case IMGTOOLINFO_STR_FILE: - strcpy( info->s = imgtool_temp_str(), __FILE__ ); break; - case IMGTOOLINFO_STR_NAME: - strcpy( info->s = imgtool_temp_str(), "thom" ); break; - case IMGTOOLINFO_STR_DESCRIPTION: - strcpy( info->s = imgtool_temp_str(), "Thomson BASIC filesystem" ); - break; - case IMGTOOLINFO_PTR_CREATE: - info->create = thom_create; break; - case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE: - info->createimage_optguide = &thom_createimage_optguide; break; - case IMGTOOLINFO_PTR_BEGIN_ENUM: - info->begin_enum = thom_begin_enum; break; - case IMGTOOLINFO_PTR_NEXT_ENUM: - info->next_enum = thom_next_enum; break; - case IMGTOOLINFO_PTR_READ_FILE: - info->read_file = thom_read_file; break; - case IMGTOOLINFO_PTR_WRITE_FILE: - info->write_file = thom_write_file; break; - case IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE: - 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; - case IMGTOOLINFO_PTR_SUGGEST_TRANSFER: - info->suggest_transfer = thom_suggest_transfer; break; - case IMGTOOLINFO_PTR_DELETE_FILE: - info->delete_file = thom_delete_file; break; - case IMGTOOLINFO_PTR_FREE_SPACE: - info->free_space = thom_free_space; break; - case IMGTOOLINFO_PTR_GET_GEOMETRY: - info->get_geometry = thom_get_geometry; break; - case IMGTOOLINFO_PTR_INFO: - info->info = thom_info; break; - case IMGTOOLINFO_PTR_READ_SECTOR: - info->read_sector = thom_read_sector; break; - case IMGTOOLINFO_PTR_WRITE_SECTOR: - info->write_sector = thom_write_sector; break; - case IMGTOOLINFO_PTR_LIST_PARTITIONS: - info->list_partitions = thom_list_partitions; break; - case IMGTOOLINFO_PTR_OPEN_PARTITION: - info->open_partition = thom_open_partition; break; - } -} - -void thom_fd_basic_get_info(const imgtool_class *clas, - uint32_t param, - union imgtoolinfo *info) -{ - switch ( param ) { - case IMGTOOLINFO_STR_NAME: - 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; - case IMGTOOLINFO_STR_FILE_EXTENSIONS: - strcpy( info->s = imgtool_temp_str(), "fd" ); break; - case IMGTOOLINFO_PTR_OPEN: - info->open = thom_open_fd_qd; break; - case IMGTOOLINFO_PTR_CLOSE: - 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; - default: - thom_basic_get_info( clas, param, info ); - } -} - -void thom_qd_basic_get_info(const imgtool_class *clas, - uint32_t param, - union imgtoolinfo *info) -{ - switch ( param ) { - case IMGTOOLINFO_STR_NAME: - 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; - case IMGTOOLINFO_STR_FILE_EXTENSIONS: - strcpy( info->s = imgtool_temp_str(), "qd" ); break; - case IMGTOOLINFO_PTR_OPEN: - info->open = thom_open_fd_qd; break; - case IMGTOOLINFO_PTR_CLOSE: - 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; - default: - thom_basic_get_info( clas, param, info ); - } -} - -void thom_sap_basic_get_info(const imgtool_class *clas, - uint32_t param, - union imgtoolinfo *info) -{ - switch ( param ) { - case IMGTOOLINFO_STR_NAME: - 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; - case IMGTOOLINFO_STR_FILE_EXTENSIONS: - strcpy( info->s = imgtool_temp_str(), "sap" ); break; - case IMGTOOLINFO_PTR_OPEN: - info->open = thom_open_sap; break; - case IMGTOOLINFO_PTR_CLOSE: - 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; - default: - thom_basic_get_info( clas, param, info ); - } -} diff --git a/src/tools/imgtool/modules/ti99.cpp b/src/tools/imgtool/modules/ti99.cpp deleted file mode 100644 index 37367a8..0000000 --- a/src/tools/imgtool/modules/ti99.cpp +++ /dev/null @@ -1,5368 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Raphael Nabet -/* - Handlers for ti99 disk images - - We support the following types of image: - * floppy disks ("DSK format") in v9t9, pc99 and old mess image format - * hard disks ("WIN format") in MAME harddisk format (256-byte sectors only, - i.e. no SCSI) - Files are extracted in TIFILES format. There is a compile-time option to - extract text files in flat format instead, but I need to re-implement it - properly (using filters comes to mind). - - Raphael Nabet, 2002-2004 - - TODO: - - finish and test hd support ***test sibling FDR support*** - - check allocation bitmap against corruption when an image is opened -*/ - -#include "imgtool.h" -#include "harddisk.h" -#include "imghd.h" - -#include "opresolv.h" - -#include -#include -#include -#include -#include - -/* - Concepts shared by both disk structures: - ---------------------------------------- - - In both formats, the entire disk surface is split into physical records, - each 256-byte-long. For best efficiency, the sector size is usually 256 - bytes so that one sector is equivalent to a physical record (this is true - with floppies and HFDC hard disks). If the sector size is not 256 bytes - (e.g. 512 bytes with SCSI hard disks, possibly 128 bytes on a TI-99 - simulator running on TI-990), sectors are grouped or split to form 256-byte - physical records. Physical records are numbered from 0, with the first - starting on sector 0 track 0. To avoid confusion with physical records in - files, such physical records will be called "absolute physical records", - abbreviated as "absolute physrecs" or "aphysrecs". - - Disk space is allocated in units referred to as AUs. Each AU represents an - integral number of 256-byte physical records. The number of physrecs per - AU varies depending on the disk format and size. AUs are numbered from 0, - with the first starting with absolute physrec 0. - - Absolute physrec 0 contains a 256-byte record with volume information, - which is called "Volume Information Block", abbreviated as "vib". - - To keep track of which areas on the disk are allocated and which are free, - disk managers maintain a bit map of allocated AUs (called "allocation - bitmap", abbreviated as "abm"). Each bit in the allocation bitmap - represents an AU: if a bit is 0, the AU is free; if a bit is 1, the AU is - allocated (or possibly bad if the disk manager can track bad sectors). - Where on the disk the abm is located depends on the disk structure (see - structure-specific description for details). - - Files are implemented as a succession of 256-byte physical records. To - avoid confusion with absolute physical records, these physical records will - be called "file physical records", abbreviated as "file physrecs" or - "fphysrecs". - - Programs do normally not access file physical records directly. They may - call high-level file routines that enable to create either fixed-length - logical records of any size from 1 through 255, or variable-length records - of any size from 0 through 254: logical records are grouped by file - managers into 256-byte physical records. Some disk managers (HFDC and - SCSI) allow programs to create fixed-length records larger than 255 bytes, - too, but few programs use this possibility. Additionally, program files - can be created: program files do not implement any logical record, and can - be seen as a flat byte stream, not unlike files under MSDOS, UNIX and the C - standard library. (Unfortunately, the API for program files lacks - flexibility, and most programs that need to process a flat byte stream - will use fixed-size records of 128 bytes.) - - Fixed-length records (reclen < 256) are grouped like this: - fphysrec 0 fphysrec 1 - _______________ _______________ - |R0 |R1 |R2 |X| |R3 |R4 |R5 |X| - --------------- --------------- - \_/ \_/ - unused unused - (size < reclen) (size < reclen) - - Fixed-length records (reclen > 256) are grouped like this: - fphysrec 0 fphysrec 1 fphysrec 2 fphysrec 3 ... - _________________ _________________ _________________ _________________ - | R0 (#0-255) | | R0 (#256-511) | |R0 (#512-end)|X| | R1 (#0-255) | ... - ----------------- ----------------- ----------------- ----------------- - \_/ - unused - - Variable length records are grouped like this: - fphysrec 0: - byte: - ------------------------------ - 0 |l0 = length of record 0 data| - |----------------------------| - 1 | | - | | - : | record 0 data | - | | - l0 | | - |----------------------------| - l0+1 |l1 = length of record 1 data| - |----------------------------| - l0+2 | | - | | - : | record 1 data | - | | - l0+l1+1 | | - |----------------------------| - : : : - : : : - |----------------------------| - n |lm = length of record m data| - |----------------------------| - n+1 | | - | | - : | record m data | - | | - n+lm | | - |----------------------------| - n+lm+1 |>ff: EOR mark | - |----------------------------| - n+lm+2 | | - | | - : | unused | - : |(we should have size < lm+1)| - | | - 255 | | - ------------------------------ - - fphysrec 1: - byte: - ------------------------------ - 0 |lm+1=length of record 0 data| - |----------------------------| - 1 | | - | | - : | record m+1 data | - | | - lm+1 | | - |----------------------------| - : : : - : : : - - I think the EOR mark is not required if all 256 bytes of a physical - record are used by logical records. - - - All files are associated with a "file descriptor record" ("fdr") that holds - file information (name, format, length) and points to the data AUs. The WIN - disk structure also supports sibling FDRs, in case a file is so fragmented - that all the data pointers cannot fit in one FDR; the DSK disk structure - does not implement any such feature, and you may be unable to append data - to an existing file if it is too fragmented, even though the disk is not - full. - - - DSK disk structure: - ------------------- - - 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 - 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 - know anything about either). - - For some reason, the number of physrecs per AU is always a power of 2. - Originally, AUs always were one physical record each. However, since the - allocation bitmap cannot support more than 1600 AUs, disks larger than - 400kbytes need to have several physical records per AU. Note that - relatively few disk controllers implement AUs that span multiple physical - records (IIRC, these are Myarc's HFDC, SCSI DSR with floppy disk interface, - and some upgraded Myarc and Corcomp DD floppy controllers). - - The allocation bitmap is located in the VIB. It is 200 bytes long, and - supports 1600 AUs at most. - - Directories are implemented with a "File Descriptor Index Record" (FDIR) - for each directory. The FDIR is array of 0 through 128 words, containing - the aphysrec address of each fdr in the directory, sorted by ascending file - name, terminated with a 0. Note that, while we should be prepared to read - images images with 128 entries, I think (not 100% sure) that we should - write no more than 127 for compatibility with some existing disk managers. - - Originally, the DSK structure only supported one directory level (i.e. the - root directory level). The FDIR record for the root directory is always - located in aphysrec 1. Moreover, Myarc extended the DSK structure to - support up to 3 subdirectories in the root directory (note that there is no - support for more subdirs, or for subdirs located in subdirs). To do so, - they used an unused field of the VIB to hold the 10-char name of each - directory and the aphysrec address of the associated FDIR record. - - aphysrec 0: Volume Information Block (VIB): see below - aphysrec 1: FDIR for root directory - Remaining AUs are used for fdr and data (and subdirectory FDIR if - applicable). There is one FDIR record per directory; the FDIR points to - the FDR for each file in the directory. The FDR (File Descriptor Record) - contains the file information (name, format, length, pointers to data - physrecs/AUs, etc). - - - WIN disk structure: - ------------------- - - The WIN disk structure is used for hard disks. It supports 65535 AUs and - 256 MBytes at most. - - The disk sector size is 256 bytes on HFDC, 512 bytes on SCSI. 512-byte - sectors are split into 256-byte physical records. - - We may have from 1 through 16 physrecs per AUs. Since we cannot have more - than 65535 AUs, we need to have several physical records per AU in disks - larger than 16 Mbytes. - - Contrary to the DSK disk structure, the WIN disk structure supports - hierarchic subdirectories, with a limit of 114 subdirectories and 127 files - per directory. Each directory is associated with both a "Directory - Descriptor Record" (DDR) and a "File Descriptor Index Record" (FDIR). The - only exception is the root directory, which uses the VIB instead of a DDR - (the VIB includes all the important fields of the DDR). The DDR contains - some directory info (name, number of files and subdirectories directly - enclosed in the directory, AU address of the FDIR of the parent directory, - etc), the AU address of the associated FDIR, and the AU address of the DDR - of up to 114 subdirectories, sorted by ascending directory name. The WIN - FDIR is similar to, yet different from, the DSK FDIR: it contains up to 127 - (vs. 128) AU address (vs. aphysrec address) of each fdr in the directory, - sorted by ascending file name. Additionally, it includes the AU address of - the associated DDR. - - When a file has more than 54 data fragments, the disk manager creates - sibling FDRs that hold additional fragments. (Sibling FDRs are called - offspring FDRs in most existing documentation, but I prefer "sibling FDRs" - as "offspring FDRs" wrongly suggests a directory-like hierarchy. - Incidentally, I cannot really figure out why they chose to duplicate the - FDR rather than create a file extension record, but there must be a - reason.) Note that sibling FDRs usually fill unused physrecs in the AU - allocated for the eldest FDR, and a new AU is allocated for new sibling - FDRs only when the first AU is full. - - aphysrec 0: Volume Information Block (VIB): see below - aphysrec 1-n (where n = 1+SUP(number_of_AUs/2048)): Volume bitmap - Remaining AUs are used for ddr, fdir, fdr and data. -*/ - -/* Since string length is encoded with a byte, the maximum length of a string -is 255. Since we need to add a device name (1 char minimum, typically 4 chars) -and a '.' separator, we chose a practical value of 250 (though few applications -will accept paths of such length). */ -#define MAX_PATH_LEN 253 -#define MAX_SAFE_PATH_LEN 250 - -#define MAX_DIR_LEVEL 125 /* We need to put a recursion limit to avoid endless recursion hazard */ - - -#if 0 -#pragma mark MISCELLANEOUS UTILITIES -#endif - -/* - Miscellaneous utilities that are used to handle TI data types -*/ - -struct UINT16BE -{ - uint8_t bytes[2]; -}; - -struct UINT16LE -{ - uint8_t bytes[2]; -}; - -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; -} - -static inline uint16_t get_UINT16LE(UINT16LE word) -{ - return word.bytes[0] | (word.bytes[1] << 8); -} - -static inline void set_UINT16LE(UINT16LE *word, uint16_t data) -{ - word->bytes[0] = data & 0xff; - word->bytes[1] = (data >> 8) & 0xff; -} - -/* - Convert a C string to a 10-character file name (padded with spaces if necessary) - - dst (O): destination 10-character array - src (I): source C string -*/ -static void str_to_fname(char dst[10], const char *src) -{ - int i; - - - i = 0; - - /* copy 10 characters at most */ - if (src) - while ((i<10) && (src[i]!='\0')) - { - dst[i] = src[i]; - i++; - } - - /* pad with spaces */ - while (i<10) - { - dst[i] = ' '; - i++; - } -} - -/* - Convert a 10-character file name to a C string (removing trailing spaces if necessary) - - dst (O): destination C string - src (I): source 10-character array - n (I): length of dst buffer (string may be truncated if less than 11) -*/ -static void fname_to_str(char *dst, const char src[10], int n) -{ - int i; - int last_nonspace; - - - /* copy 10 characters at most */ - if (--n > 10) - n = 10; - - /* copy filename */ - i = 0; - last_nonspace = -1; - - while (i MAX_PATH_LEN) || strchr(fpath, ' ')) - return 1; - - /* check that each path element has an acceptable length */ - element_start = fpath; - do - { - /* find next path element */ - element_end = strchr(element_start, '.'); - element_len = element_end ? (element_end - element_start) : strlen(element_start); - if ((element_len > 10) || (element_len == 0)) - return 1; - - /* iterate */ - if (element_end) - element_start = element_end+1; - else - element_start = NULL; - } - while (element_start); - - return 0; -} - -#if 0 -#pragma mark - -#pragma mark LEVEL 1 DISK ROUTINES -#endif - -/* - Level 1 deals with accessing the disk hardware (in our case, the raw disk - image). - - Higher level routines will only know the disk as a succession of - 256-byte-long physical records addressed by a linear address. -*/ - -/* - Disk geometry -*/ -struct ti99_geometry -{ - int secspertrack; - int cylinders; - int heads; -}; - -/* - Physical sector address -*/ -struct ti99_sector_address -{ - int sector; - int cylinder; - int side; -}; - -/* - Time stamp (used in fdr, and WIN VIB/DDR) -*/ -struct ti99_date_time -{ - uint8_t time_MSB, time_LSB;/* 0-4: hour, 5-10: minutes, 11-15: seconds/2 */ - uint8_t date_MSB, date_LSB;/* 0-6: year, 7-10: month, 11-15: day */ -}; - -/* - Subdirectory descriptor (HFDC only) - - The HFDC supports up to 3 subdirectories. -*/ -struct dsk_subdir -{ - char name[10]; /* subdirectory name (10 characters, pad with spaces) */ - UINT16BE fdir_aphysrec; /* aphysrec address of fdir record for this subdirectory */ -}; - -/* - DSK VIB record - - Most fields in this record are only relevant to level 2 routines, but level - 1 routines need the disk geometry information extracted from the VIB. -*/ -struct dsk_vib -{ - char name[10]; /* disk volume name (10 characters, pad with spaces) */ - UINT16BE totphysrecs; /* total number of physrecs on disk (usually 360, */ - /* 720, 640, 1280 or 1440). (TI originally */ - /* said it should be the total number of AUs, */ - /* but, in practice, DSRs that supports disks */ - /* over 400kbytes (e.g. HFDC) write the total */ - /* number of physrecs.) */ - uint8_t secspertrack; /* sectors per track (usually 9 (FM SD), */ - /* 16 or 18 (MFM DD), or 36 (MFM HD) */ - uint8_t id[3]; /* 'DSK' */ - uint8_t protection; /* 'P' if disk is protected, ' ' otherwise. */ - uint8_t cylinders; /* tracks per side (usually 40) */ - uint8_t heads; /* sides (1 or 2) */ - uint8_t density; /* density: 1 (FM SD), 2 (MFM DD), or 3 (MFM HD) */ - dsk_subdir subdir[3]; /* descriptor for up to 3 subdirectories (HFDC only) */ - /* reserved by TI */ - uint8_t abm[200]; /* allocation bitmap: there is one bit per AU. */ - /* A binary 1 in a bit position indicates that */ - /* the allocation unit associated with that */ - /* bit has been allocated. */ - /* Bits corresponding to system reserved AUs, */ - /* 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.) */ -}; - -enum ti99_img_format -{ - if_mess, - if_v9t9, - if_pc99_fm, - if_pc99_mfm, - if_harddisk -}; - -/* - level-1 disk image descriptor -*/ -struct ti99_lvl1_imgref -{ - ti99_img_format img_format; /* tells the image format */ - imgtool::stream *file_handle; /* imgtool file handle */ - struct mess_hard_disk_file harddisk_handle; /* MAME harddisk handle (harddisk format) */ - ti99_geometry geometry; /* geometry */ - unsigned pc99_track_len; /* unformatted track length (pc99 format) */ - uint32_t *pc99_data_offset_array; /* offset for each sector (pc99 format) */ -}; - -/* - calculate CRC for data address marks or sector data - - crc (I/O): current CRC value to be updated (initialize to 0xffff before - calling this function for the first time) - value: new byte of data to update the CRC with -*/ -static void calc_crc(uint16_t *crc, uint8_t value) -{ - uint8_t l, h; - - l = value ^ (*crc >> 8); - *crc = (*crc & 0xff) | (l << 8); - l >>= 4; - l ^= (*crc >> 8); - *crc <<= 8; - *crc = (*crc & 0xff00) | l; - l = (l << 4) | (l >> 4); - h = l; - l = (l << 2) | (l >> 6); - l &= 0x1f; - *crc = *crc ^ (l << 8); - l = h & 0xf0; - *crc = *crc ^ (l << 8); - l = (h << 1) | (h >> 7); - l &= 0xe0; - *crc = *crc ^ l; -} - -/* - Parse a PC99 disk image - - file_handle (I/O): imgtool file handle - fm_format (I): if true, the image is in FM format, otherwise it is in MFM - format - pass (I): 0 for first pass, 1 for second pass - vib (O): buffer where the vib should be stored (first pass) - geometry (O): disk image geometry (second pass) - data_offset_array (O): array of data offset to generate (second pass) - out_track_len (O): track length is returned there - - Return imgtool error code -*/ -#define MAX_TRACK_LEN 6872 -#define DATA_OFFSET_NONE 0xffffffff -static int parse_pc99_image(imgtool::stream &file_handle, int fm_format, int pass, dsk_vib *vib, const ti99_geometry *geometry, uint32_t *data_offset_array, unsigned *out_track_len) -{ - int track_len, num_tracks; /* length of a track in bytes, and number of tracks */ - int phys_track; - int expected_cylinder, expected_head; - int track_start_pos, track_pos; - uint8_t c; - uint8_t cylinder, head, sector; - int seclen; - uint8_t crc1, crc2; - uint16_t crc; - long data_offset; - uint8_t track_buf[MAX_TRACK_LEN]; - int i; - - if (fm_format) - track_len = 3253; - else - track_len = 6872; - - if (out_track_len) - *out_track_len = track_len; - - if (file_handle.size() % track_len) - return IMGTOOLERR_CORRUPTIMAGE; - - num_tracks = file_handle.size() / track_len; - if (num_tracks <= 0) - return IMGTOOLERR_CORRUPTIMAGE; - - /* we only support 40-track-per-side images */ - if ((num_tracks != 40) && (num_tracks != 80)) - return IMGTOOLERR_UNIMPLEMENTED; - - if (pass == 1) - { - /* initialize offset map */ - for (head = 0; head < geometry->heads; head++) - for (cylinder = 0; cylinder < geometry->cylinders; cylinder++) - for (sector = 0; sector < geometry->secspertrack; sector++) - data_offset_array[(head*geometry->cylinders + cylinder)*geometry->secspertrack + sector] = DATA_OFFSET_NONE; - } - /* rewind to start of file */ - file_handle.seek(0, SEEK_SET); - - /* pass 0 only looks for vib in track 0; pass 1 scans every track */ - for (phys_track=0; phys_track < ((pass == 1) ? num_tracks : 1); phys_track++) - { - if (file_handle.read(track_buf, track_len) != track_len) - return IMGTOOLERR_READERROR; - - /* we only support 40-track-per-side images */ - expected_cylinder = phys_track % 40; - expected_head = phys_track / 40; - - track_start_pos = 0; - - while (track_start_pos < track_len) - { - if (fm_format) - { - do - { - c = track_buf[track_start_pos]; - track_start_pos++; - } while ((c != 0xfe) && (track_start_pos < track_len)); - - if (c != 0xfe) - break; - - track_pos = track_start_pos; - - crc = 0xffff; - calc_crc(& crc, c); - } - else - { - do - { - c = track_buf[track_start_pos]; - track_start_pos++; - } while ((c != 0xa1) && (track_start_pos < track_len)); - - if (c != 0xa1) - break; - - track_pos = track_start_pos; - - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - - if (c != 0xa1) - continue; - - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - - if (c != 0xa1) - continue; - - crc = 0xffff; - calc_crc(& crc, c); - - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - - if (c != 0xfe) - continue; - } - - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - - cylinder = c; - calc_crc(& crc, c); - - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - - head = c; - calc_crc(& crc, c); - - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - - sector = c; - calc_crc(& crc, c); - - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - - seclen = 128 << c; - calc_crc(& crc, c); - - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - - crc1 = c; - calc_crc(& crc, c); - - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - - crc2 = c; - calc_crc(& crc, c); - -#if 0 - /* CRC seems to be completely hosed */ - if (crc) - printf("aargh!"); -#endif - if ((seclen != 256) || (crc1 != 0xf7) || (crc2 != 0xf7) - || (cylinder != expected_cylinder) || (head != expected_head) - || ((pass == 1) && ((cylinder >= geometry->cylinders) - || (head >= geometry->heads) - || (sector >= geometry->secspertrack)))) - continue; - - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - - while (c == (fm_format ? 0xff : 0x4e)) - { - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - } - - while (c == 0x00) - { - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - } - - if (fm_format) - { - if (c != 0xfb) - continue; - - crc = 0xffff; - calc_crc(& crc, c); - } - else - { - if (c != 0xa1) - continue; - - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - - if (c != 0xa1) - continue; - - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - - if (c != 0xa1) - continue; - - crc = 0xffff; - calc_crc(& crc, c); - - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - - if (c != 0xfb) - continue; - } - data_offset = track_pos; - for (i=0; icylinders + cylinder)*geometry->secspertrack + sector] != DATA_OFFSET_NONE) - /* error: duplicate sector */ - return IMGTOOLERR_CORRUPTIMAGE; - data_offset_array[(head*geometry->cylinders + cylinder)*geometry->secspertrack + sector] = data_offset; - break; - } - } - } - - if (pass == 0) - return IMGTOOLERR_CORRUPTIMAGE; - - if (pass == 1) - { - /* check offset map */ - for (head = 0; head < geometry->heads; head++) - for (cylinder = 0; cylinder < geometry->cylinders; cylinder++) - for (sector = 0; sector < geometry->secspertrack; sector++) - if (data_offset_array[(head*geometry->cylinders + cylinder)*geometry->secspertrack + sector] == DATA_OFFSET_NONE) - /* error: missing sector */ - return IMGTOOLERR_CORRUPTIMAGE; - } - - return 0; -} - - -/* - Read the volume information block (aphysrec 0) assuming no geometry - information. (Called when an image is opened to figure out the - geometry information.) - - file_handle (I/O): imgtool file handle - img_format (I): image format (MESS, V9T9 or PC99) - dest (O): pointer to 256-byte destination buffer - - Return imgtool error code -*/ -static int read_image_vib_no_geometry(imgtool::stream &file_handle, ti99_img_format img_format, dsk_vib *dest) -{ - int reply; - - switch (img_format) - { - case if_mess: - case if_v9t9: - /* seek to sector */ - reply = file_handle.seek(0, SEEK_SET); - if (reply) - return IMGTOOLERR_READERROR; - /* read it */ - reply = file_handle.read(dest, 256); - if (reply != 256) - return IMGTOOLERR_READERROR; - return 0; - - case if_pc99_fm: - case if_pc99_mfm: - return parse_pc99_image(file_handle, img_format == if_pc99_fm, 0, dest, NULL, NULL, NULL); - - case if_harddisk: - /* not implemented, because we don't need it */ - break; - } - - return IMGTOOLERR_UNIMPLEMENTED; -} - -/* - Open a disk image at level 1 - - file_handle (I/O): imgtool file handle - img_format (I): image format (MESS, V9T9, PC99, or MAME harddisk) - l1_img (O): level-1 image handle - vib (O): buffer where the vib should be stored (floppy images only) - - Return imgtool error code -*/ -static imgtoolerr_t open_image_lvl1(imgtool::stream::ptr &&file_handle, ti99_img_format img_format, ti99_lvl1_imgref *l1_img, dsk_vib *vib) -{ - imgtoolerr_t err; - int reply; - uint16_t totphysrecs; - - l1_img->img_format = img_format; - - 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) - { - imghd_close(&l1_img->harddisk_handle); - return IMGTOOLERR_CORRUPTIMAGE; /* TODO: support 512-byte sectors */ - } - -#if 0 - /* read vib */ - reply = read_absolute_physrec(l1_img, 0, vib); - if (reply) - return reply; -#endif - } - else - { - /* read vib */ - reply = read_image_vib_no_geometry(*file_handle, img_format, vib); - if (reply) - return (imgtoolerr_t)reply; - - /* extract geometry information */ - totphysrecs = get_UINT16BE(vib->totphysrecs); - - l1_img->geometry.secspertrack = vib->secspertrack; - if (l1_img->geometry.secspertrack == 0) - /* Some images might be like this, because the original SSSD TI - controller always assumes 9. */ - l1_img->geometry.secspertrack = 9; - l1_img->geometry.cylinders = vib->cylinders; - if (l1_img->geometry.cylinders == 0) - /* Some images are like this, because the original SSSD TI - controller always assumes 40. */ - l1_img->geometry.cylinders = 40; - l1_img->geometry.heads = vib->heads; - if (l1_img->geometry.heads == 0) - /* Some images are like this, because the original SSSD TI - controller always assumes that tracks beyond 40 are on side 2. */ - l1_img->geometry.heads = totphysrecs / (l1_img->geometry.secspertrack * l1_img->geometry.cylinders); - - /* check information */ - if ((totphysrecs != (l1_img->geometry.secspertrack * l1_img->geometry.cylinders * l1_img->geometry.heads)) - || (totphysrecs < 2) - || memcmp(vib->id, "DSK", 3) || (! strchr(" P", vib->protection)) - || (((img_format == if_mess) || (img_format == if_v9t9)) - && (file_handle->size() != totphysrecs*256U))) - return (imgtoolerr_t)IMGTOOLERR_CORRUPTIMAGE; - - if ((img_format == if_pc99_fm) || (img_format == if_pc99_mfm)) - { - l1_img->pc99_data_offset_array = (uint32_t*)malloc(sizeof(*l1_img->pc99_data_offset_array)*totphysrecs); - if (! l1_img->pc99_data_offset_array) - return IMGTOOLERR_OUTOFMEMORY; - reply = parse_pc99_image(*file_handle, img_format == if_pc99_fm, 1, NULL, & l1_img->geometry, l1_img->pc99_data_offset_array, &l1_img->pc99_track_len); - if (reply) - { - free(l1_img->pc99_data_offset_array); - return (imgtoolerr_t)reply; - } - } - } - - l1_img->file_handle = file_handle.release(); // we can only do this when we're sure we're successful - - return (imgtoolerr_t)0; -} - -/* - Close a disk image at level 1 - - l1_img (I/O): level-1 image handle - - Return imgtool error code -*/ -static void close_image_lvl1(ti99_lvl1_imgref *l1_img) -{ - if (l1_img->img_format == if_harddisk) - { - imghd_close(&l1_img->harddisk_handle); - } - - delete l1_img->file_handle; - - if ((l1_img->img_format == if_pc99_fm) || (l1_img->img_format == if_pc99_mfm)) - free(l1_img->pc99_data_offset_array); -} - -/* - Convert physical sector address to offset in disk image (old MESS and V9T9 - formats only) - - l1_img (I/O): level-1 image handle - address (I): physical sector address - - Return offset in image -*/ -static inline int sector_address_to_image_offset(const ti99_lvl1_imgref *l1_img, const ti99_sector_address *address) -{ - int offset = 0; - - switch (l1_img->img_format) - { - case if_mess: - /* old MESS format */ - offset = (((address->cylinder*l1_img->geometry.heads) + address->side)*l1_img->geometry.secspertrack + address->sector)*256; - break; - - case if_v9t9: - /* V9T9 format */ - if (address->side & 1) - /* on side 1, tracks are stored in the reverse order */ - offset = (((address->side*l1_img->geometry.cylinders) + (l1_img->geometry.cylinders-1 - address->cylinder))*l1_img->geometry.secspertrack + address->sector)*256; - else - offset = (((address->side*l1_img->geometry.cylinders) + address->cylinder)*l1_img->geometry.secspertrack + address->sector)*256; - break; - - case if_pc99_fm: - case if_pc99_mfm: - /* pc99 format */ - case if_harddisk: - /* harddisk format */ - assert(1); /* not implemented */ - break; - } - - return offset; -} - -/* - Read one 256-byte sector from a disk image - - l1_img (I/O): level-1 image handle - address (I): physical sector address - dest (O): pointer to 256-byte destination buffer - - Return non-zero on error -*/ -static int read_sector(ti99_lvl1_imgref *l1_img, const ti99_sector_address *address, void *dest) -{ - int reply; - uint32_t track_len, track_offset, sector_offset; - - switch (l1_img->img_format) - { - case if_mess: - /* old MESS format */ - case if_v9t9: - /* V9T9 format */ - /* seek to sector */ - reply = l1_img->file_handle->seek(sector_address_to_image_offset(l1_img, address), SEEK_SET); - if (reply) - return 1; - /* read it */ - reply = l1_img->file_handle->read(dest, 256); - if (reply != 256) - return 1; - break; - - case if_pc99_fm: - case if_pc99_mfm: - /* pc99 format */ - track_len = l1_img->pc99_track_len; - track_offset = (address->side*l1_img->geometry.cylinders + address->cylinder)*track_len; - sector_offset = l1_img->pc99_data_offset_array[(address->side*l1_img->geometry.cylinders + address->cylinder)*l1_img->geometry.secspertrack + address->sector]; - - if ((sector_offset + 256) <= track_len) - { - /* seek to sector */ - reply = l1_img->file_handle->seek(track_offset+sector_offset, SEEK_SET); - if (reply) - return 1; - /* read it */ - reply = l1_img->file_handle->read(dest, 256); - if (reply != 256) - return 1; - } - else - { - /* seek to sector */ - reply = l1_img->file_handle->seek(track_offset+sector_offset, SEEK_SET); - if (reply) - return 1; - /* read first chunk (until end of track) */ - reply = l1_img->file_handle->read((uint8_t *)dest, track_len-sector_offset); - if (reply != track_len-sector_offset) - return 1; - - /* wrap to start of track */ - reply = l1_img->file_handle->seek(track_offset, SEEK_SET); - if (reply) - return 1; - /* read remnant of sector */ - reply = l1_img->file_handle->read((uint8_t *)dest + (track_len-sector_offset), 256-(track_len-sector_offset)); - if (reply != 256-(track_len-sector_offset)) - return 1; - } - break; - - case if_harddisk: - /* not implemented */ - assert(1); - /*return imghd_read(l1_img->harddisk_handle, ((address->cylinder*l1_img->geometry.heads) + address->side)*l1_img->geometry.secspertrack + address->sector, 1, dest) != 1;*/ - break; - } - - return 0; -} - -/* - Write one 256-byte sector to a disk image - - l1_img (I/O): level-1 image handle - address (I): physical sector address - src (I): pointer to 256-byte source buffer - - Return non-zero on error -*/ -static int write_sector(ti99_lvl1_imgref *l1_img, const ti99_sector_address *address, const void *src) -{ - int reply; - uint32_t track_len, track_offset, sector_offset; - - switch (l1_img->img_format) - { - case if_mess: - /* old MESS format */ - case if_v9t9: - /* V9T9 format */ - /* seek to sector */ - reply = l1_img->file_handle->seek(sector_address_to_image_offset(l1_img, address), SEEK_SET); - if (reply) - return 1; - /* write it */ - reply = l1_img->file_handle->write(src, 256); - if (reply != 256) - return 1; - break; - - case if_pc99_fm: - case if_pc99_mfm: - /* pc99 format */ - track_len = l1_img->pc99_track_len; - track_offset = (address->side*l1_img->geometry.cylinders + address->cylinder)*track_len; - sector_offset = l1_img->pc99_data_offset_array[(address->side*l1_img->geometry.cylinders + address->cylinder)*l1_img->geometry.secspertrack + address->sector]; - - if ((sector_offset + 256) <= track_len) - { - /* seek to sector */ - reply = l1_img->file_handle->seek(track_offset+sector_offset, SEEK_SET); - if (reply) - return 1; - /* write it */ - reply = l1_img->file_handle->write(src, 256); - if (reply != 256) - return 1; - } - else - { - /* seek to sector */ - reply = l1_img->file_handle->seek(track_offset+sector_offset, SEEK_SET); - if (reply) - return 1; - /* write first chunk (until end of track) */ - reply = l1_img->file_handle->write((uint8_t *)src, track_len-sector_offset); - if (reply != track_len-sector_offset) - return 1; - - /* wrap to start of track */ - reply = l1_img->file_handle->seek(track_offset, SEEK_SET); - if (reply) - return 1; - /* write remnant of sector */ - reply = l1_img->file_handle->write((uint8_t *)src + (track_len-sector_offset), 256-(track_len-sector_offset)); - if (reply != 256-(track_len-sector_offset)) - return 1; - } - break; - - case if_harddisk: - /* not implemented */ - assert(1); - /*return imghd_write(l1_img->harddisk_handle, ((address->cylinder*l1_img->geometry.heads) + address->side)*l1_img->geometry.secspertrack + address->sector, 1, src) != 1;*/ - break; - } - - return 0; -} - -/* - Convert physical record address to sector address (DSK format) - - aphysrec (I): absolute physrec address - geometry (I): disk image geometry - address (O): physical sector address -*/ -static void dsk_aphysrec_to_sector_address(int aphysrec, const ti99_geometry *geometry, ti99_sector_address *address) -{ - address->sector = aphysrec % geometry->secspertrack; - aphysrec /= geometry->secspertrack; - address->cylinder = aphysrec % geometry->cylinders; - address->side = aphysrec / geometry->cylinders; - if (address->side & 1) - /* on side 1, tracks are stored in the reverse order */ - address->cylinder = geometry->cylinders-1 - address->cylinder; -} - -/* - Convert physical record address to sector address (WIN format for HFDC) - - Note that physical address translation makes sense for HFDC, but not SCSI. - - aphysrec (I): absolute physrec address - 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) -{ - 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; -} -#endif - -/* - Read one 256-byte physical record from a disk image - - l1_img (I/O): level-1 image handle - aphysrec (I): absolute physrec address - dest (O): pointer to 256-byte destination buffer - - Return non-zero on error -*/ -static int read_absolute_physrec(ti99_lvl1_imgref *l1_img, unsigned aphysrec, void *dest) -{ - ti99_sector_address address; - - - if (l1_img->img_format == if_harddisk) - { -#if 0 - win_aphysrec_to_sector_address(aphysrec, & l1_img->geometry, & address); - return read_sector(l1_img, & address, dest); -#endif - - return imghd_read(&l1_img->harddisk_handle, aphysrec, dest) != IMGTOOLERR_SUCCESS; - } - else - { - dsk_aphysrec_to_sector_address(aphysrec, & l1_img->geometry, & address); - - return read_sector(l1_img, & address, dest); - } -} - -/* - Write one 256-byte physical record to a disk image - - l1_img (I/O): level-1 image handle - aphysrec (I): absolute physrec address - src (I): pointer to 256-byte source buffer - - Return non-zero on error -*/ -static int write_absolute_physrec(ti99_lvl1_imgref *l1_img, unsigned aphysrec, const void *src) -{ - ti99_sector_address address; - - - if (l1_img->img_format == if_harddisk) - { -#if 0 - win_aphysrec_to_sector_address(aphysrec, & l1_img->geometry, & address); - return write_sector(l1_img, & address, dest); -#endif - - return imghd_write(&l1_img->harddisk_handle, aphysrec, src) != IMGTOOLERR_SUCCESS; - } - else - { - dsk_aphysrec_to_sector_address(aphysrec, & l1_img->geometry, & address); - - return write_sector(l1_img, & address, src); - } -} - -#if 0 -#pragma mark - -#pragma mark LEVEL 2 DISK ROUTINES -#endif - -/* - Level 2 implements files as a succession of 256-byte-long physical records. - - Level 2 implements allocation bitmap (and AU), disk catalog, etc. -*/ - -/* - WIN VIB/DDR record -*/ -struct win_vib_ddr -{ - char name[10]; /* disk volume name (10 characters, pad with spaces) */ - UINT16BE totAUs; /* total number of AUs */ - uint8_t secspertrack; /* HFDC: sectors per track (typically 32) */ - /* SCSI: reserved */ - union - { - struct - { - uint8_t id[3]; /* V1 VIB: 'WIN' */ - } vib_v1; - - struct /* V2 VIB: extra params */ - { - uint8_t res_AUs; /* # AUs reserved for vib, bitmap, ddr, fdir and fdr, divided by 64 */ - uint8_t step_spd; /* HFDC: step speed (0-7) */ - /* SCSI: reserved */ - uint8_t red_w_cur;/* HFDC: reduced write current cylinder, divided by 8 */ - /* SCSI: reserved */ - } vib_v2; - - struct - { - uint8_t id[3]; /* DDR: 'DIR' */ - } ddr; - } u; - UINT16BE params; /* bits 0-3: sectors/AU - 1 */ - /* HFDC: */ - /* bits 4-7: # heads - 1 */ - /* bit 8: V1: buffered head stepping flag */ - /* V2: reserved */ - /* bit 9-15: write precompensation track, divided by 16 */ - /* SCSI: */ - /* bits 4-15: reserved */ - ti99_date_time creation;/* date and time of creation */ - uint8_t num_files; /* number of files in directory */ - uint8_t num_subdirs; /* number of subdirectories in directory */ - UINT16BE fdir_AU; /* points to root directory fdir */ - union - { - struct - { - UINT16BE dsk1_AU; /* HFDC: points to current dsk1 emulation image (0 if none) */ - /* SCSI: reserved */ - } vib; - - struct - { - UINT16BE parent_ddr_AU; /* points to parent directory DDR */ - } ddr; - } u2; - UINT16BE subdir_AU[114];/* points to all subdirectory DDRs */ -}; - -/* - AU format -*/ -struct ti99_AUformat -{ - int totAUs; /* total number of AUs */ - int physrecsperAU; /* number of 256-byte physical records per AU */ -}; - -/* - DSK directory reference: 0 for root, 1 for 1st subdir, 2 for 2nd subdir, 3 - for 3rd subdir -*/ -/*typedef int dir_ref;*/ - -/* - catalog entry (used for in-memory catalog) -*/ -struct dir_entry -{ - uint16_t dir_ptr; /* DSK: unused */ - /* WIN: AU address of the DDR for this directory */ - char name[10]; /* name of this directory (copied from the VIB for DSK, DDR for WIN) */ -}; - -struct file_entry -{ - uint16_t fdr_ptr; /* DSK: aphysrec address of the FDR for this file */ - /* WIN: AU address of the FDR for this file */ - char name[10]; /* name of this file (copied from FDR) */ -}; - -struct ti99_catalog -{ - int num_subdirs; /* number of subdirectories */ - int num_files; /* number of files */ - dir_entry subdirs[114]; /* description of each subdir */ - file_entry files[128]; /* description of each file */ -}; - -/* - level-2 disk image descriptor -*/ -struct ti99_lvl2_imgref_dsk -{ - uint16_t totphysrecs; /* total number of aphysrecs (extracted from vib record in aphysrec 0) */ - ti99_catalog catalogs[4]; /* catalog of root directory and up to 3 subdirectories */ - uint16_t fdir_aphysrec[4]; /* fdir aphysrec address for root directory - and up to 3 subdirectories */ -}; - -enum win_vib_t -{ - win_vib_v1, - win_vib_v2 -}; -struct ti99_lvl2_imgref_win -{ - win_vib_t vib_version; /* version of the vib record in aphysrec 0 (see win_vib_ddr) */ -}; - -enum l2i_t -{ - L2I_DSK, - L2I_WIN -}; - -struct ti99_lvl2_imgref -{ - ti99_lvl1_imgref l1_img;/* image format, imgtool image handle, image geometry */ - ti99_AUformat AUformat; /* AU format */ - int data_offset; /* In order to reduce seek times when searching the - disk for a given file name, fdr (and ddr, and - fdir) records are preferentially allocated in - AUs n to data_offset, whereas data records are - preferentially allocated in AUs starting at - data_offset. */ - /* With the DSK disk structure, n is always 2 (if 1 - physrec per AU) or 1 (if 2 physrecs per AU or - more), and data_offset is arbitrarily chosen as - 34. */ - /* With the WIN disk structure, n depends on the - size of the volume bitmap, which itself depends - on the number of AUs on disk (we always have n - <= 33), and data_offset is read from the vib - record (except with the obsolete v1 VIB, where - we use a default value of 64). */ - char vol_name[10]; /* cached volume name (extracted from vib record in aphysrec 0) */ - - uint8_t abm[8192]; /* allocation bitmap */ - - l2i_t type; /* structure format */ - - union - { - ti99_lvl2_imgref_dsk dsk; - ti99_lvl2_imgref_win win; - }; /* structure-specific info */ -}; - -/* - file flags found in fdr (and tifiles) -*/ -enum -{ - fdr99_f_program = 0x01, /* set for program files */ - fdr99_f_int = 0x02, /* set for binary files */ - fdr99_f_wp = 0x08, /* set if file is write-protected */ - /*fdr99_f_backup = 0x10,*/ /* set if file has been modified since last backup */ - /*fdr99_f_dskimg = 0x20,*/ /* set if file is a DSK image (HFDC HD only) */ - fdr99_f_var = 0x80 /* set if file uses variable-length records*/ -}; - -/* - DSK FDR record -*/ -struct dsk_fdr -{ - char name[10]; /* file name (10 characters, pad with spaces) */ - 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, */ - /* but this was never implemented. */ - uint8_t flags; /* file status flags (see enum above) */ - uint8_t recsperphysrec; /* logical records per physrec */ - /* ignored for variable length record files and */ - /* program files */ - UINT16BE fphysrecs; /* file length in physrecs */ - /* Note that the HFDC defines this field as the */ - /* number of allocated physrecs in the cluster */ - /* chain (i.e. rounded on the next AU */ - /* boundary), so level-3 routines should use */ - /* the fixrecs field instead to determine the */ - /* logical length of field. IIRC, the HFDC */ - /* 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 than they should. */ - uint8_t eof; /* EOF offset in last physrec for variable length */ - /* 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 */ - /* files (set to 0). Set to 0 if reclen >=256 */ - /* (HFDC only). */ - UINT16LE fixrecs; /* file length in logical records */ - /* For variable length record files, number of */ - /* 256-byte records actually used. */ - ti99_date_time creation;/* date and time of creation (HFDC and BwG only; */ - /* reserved in TI) */ - ti99_date_time update; /* date and time of last write to file (HFDC and */ - /* BwG only; reserved in TI) */ - uint8_t clusters[76][3]; /* data cluster table: 0 through 76 entries (3 */ - /* bytes each), one entry for each file cluster. */ - /* 12 bits: address of first AU of cluster */ - /* 12 bits: offset of last 256-byte record in cluster */ -}; - -/* - WIN FDR record -*/ -struct win_fdr -{ - char name[10]; /* file name (10 characters, pad with spaces) */ - 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, */ - /* but this was never implemented. */ - uint8_t flags; /* file status flags (see enum above) */ - uint8_t recsperphysrec; /* logical records per physrec */ - /* ignored for variable length record files and */ - /* program files */ - UINT16BE fphysrecs_LSW; /* eldest FDR: file length in physrecs */ - /* Note that the HFDC defines this field as the */ - /* number of allocated physrecs in the cluster */ - /* chain (i.e. rounded on the next AU */ - /* boundary), so level-3 routines should use */ - /* the fixrecs field instead to determine the */ - /* logical length of field. IIRC, the HFDC */ - /* 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 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 */ - /* record files and program files (0->256)*/ - uint8_t reclen; /* logical record size in bytes ([1,255]) */ - /* Maximum allowable record size for variable */ - /* length record files. Reserved for program */ - /* files (set to 0). Set to 0 if reclen >=256 */ - /* (HFDC only). */ - UINT16LE fixrecs_LSW; /* file length in logical records */ - /* For variable length record files, number of */ - /* 256-byte records actually used. */ - ti99_date_time creation;/* date and time of creation */ - ti99_date_time update; /* date and time of last write to file */ - - char id[2]; /* 'FI' */ - UINT16BE prevsibFDR_AU; /* address of the AU where previous sibling FDR is */ - /* (see also xinfo_LSB) */ - UINT16BE nextsibFDR_AU; /* address of the AU where next sibling FDR is */ - /* (see also xinfo_LSB) */ - UINT16BE sibFDR_AUlen; /* total number of data AUs allocated in this particular sibling FDR */ - UINT16BE parent_FDIR_AU;/* FDIR the file is listed in */ - uint8_t xinfo_MSB; /* extended information (MSByte) */ - /* bits 0-3: MSN of fphysrecs */ - /* bits 4-7: MSN of fixrecs */ - uint8_t xinfo_LSB; /* extended information (LSByte) */ - /* bits 8-11: physrec offset within AU for */ - /* previous sibling FDR (see prevsibFDR_AU) */ - /* bits 12-15: physrec offset within AU for */ - /* next sibling FDR (see nextsibFDR_AU) */ - UINT16BE clusters[54][2];/* data cluster table: 0 through 54 entries (4 */ - /* bytes each), one entry for each file cluster. */ - /* 16 bits: address of first AU of cluster */ - /* 16 bits: address of last AU of cluster */ -}; - -/* - tifile header: stand-alone file -*/ -struct tifile_header -{ - char tifiles[8]; /* always '\7TIFILES' */ - UINT16BE fphysrecs; /* file length in physrecs */ - uint8_t flags; /* see enum above */ - uint8_t recsperphysrec; /* records per physrec */ - uint8_t eof; /* current position of eof in last physrec (0->255)*/ - uint8_t reclen; /* bytes per record ([1,255] 0->256) */ - UINT16BE fixrecs; /* file length in records */ - uint8_t res[128-16]; /* reserved */ - /* * variant a: */ - /* 112 chars: 0xCA53 repeated 56 times */ - /* * variant b: */ - /* 4 chars: unknown */ - /* 108 chars: 0xCA53 repeated 54 times */ - /* * variant c: */ - /* 10 chars: original TI file name filed with spaces */ - /* 102 chars: spaces */ - /* * variant d: */ - /* 10 chars: original TI file name filed with spaces */ - /* 2 chars: CR+LF */ - /* 98 chars: spaces */ - /* 2 chars: CR+LF */ - /* * variant e: */ - /* 10 chars: original TI file name */ - /* 4 bytes: unknown */ - /* 4 bytes: time & date of creation */ - /* 4 bytes: time & date of last update */ - /* 90 chars: spaces */ - /* * variant f: */ - /* 6 bytes: 'MYTERM' */ - /* 4 bytes: time & date of creation */ - /* 4 bytes: time & date of last update */ - /* 2 bytes: unknown (always >0000) */ - /* 96 chars: 0xCA53 repeated 56 times */ -}; - -/* - level-2 file descriptor -*/ -struct ti99_lvl2_fileref_dsk -{ - struct ti99_lvl2_imgref *l2_img; - int fdr_aphysrec; - dsk_fdr fdr; -}; - -struct ti99_lvl2_fileref_win -{ - struct ti99_lvl2_imgref *l2_img; - unsigned fphysrecs; /* copy of field in the eldest FDR */ - unsigned eldestfdr_aphysrec; /* aphysrec address of the eldest FDR */ - unsigned curfdr_aphysrec; /* aphysrec address of the currently open sibling FDR */ - win_fdr curfdr; /* buffer with currently open sibling FDR */ -}; - -struct ti99_lvl2_fileref_tifiles -{ - imgtool::stream *file_handle; - tifile_header hdr; -}; - -enum l2f_type_t -{ - L2F_DSK, - L2F_WIN, - L2F_TIFILES -}; - -struct ti99_lvl2_fileref -{ - l2f_type_t type; - union - { - ti99_lvl2_fileref_dsk dsk; - ti99_lvl2_fileref_win win; - ti99_lvl2_fileref_tifiles tifiles; - }; -}; - -static struct ti99_lvl2_imgref *get_lvl2_imgref(imgtool::image &image) -{ - return (struct ti99_lvl2_imgref *) image.extra_bytes(); -} - -/* - Compare two (possibly empty) catalog entry for qsort -*/ -static int cat_file_compare_qsort(const void *p1, const void *p2) -{ - const file_entry *entry1 = (const file_entry *)p1; - const file_entry *entry2 = (const file_entry *)p2; - - if ((entry1->fdr_ptr == 0) && (entry2->fdr_ptr == 0)) - return 0; - else if (entry1->fdr_ptr == 0) - return +1; - else if (entry2->fdr_ptr == 0) - return -1; - else - return memcmp(entry1->name, entry2->name, 10); -} - -static int cat_dir_compare_qsort(const void *p1, const void *p2) -{ - const dir_entry *entry1 = (const dir_entry *)p1; - const dir_entry *entry2 = (const dir_entry *)p2; - - if ((entry1->dir_ptr == 0) && (entry2->dir_ptr == 0)) - return 0; - else if (entry1->dir_ptr == 0) - return +1; - else if (entry2->dir_ptr == 0) - return -1; - else - return memcmp(entry1->name, entry2->name, 10); -} - -/* - Read a directory catalog from disk image - - l2_img: image reference - aphysrec: physical record address of the FDIR - dest: pointer to the destination buffer where the catalog should be written - - Return an error code if there was an error, 0 otherwise. -*/ -static int dsk_read_catalog(struct ti99_lvl2_imgref *l2_img, int aphysrec, ti99_catalog *dest) -{ - int totphysrecs = l2_img->dsk.totphysrecs; - UINT16BE fdir_buf[128]; - dsk_fdr fdr; - int i; - int reply; - - - /* Read FDIR record */ - reply = read_absolute_physrec(& l2_img->l1_img, aphysrec, fdir_buf); - if (reply) - return IMGTOOLERR_READERROR; - - /* Copy FDIR info to catalog structure */ - for (i=0; i<128; i++) - dest->files[i].fdr_ptr = get_UINT16BE(fdir_buf[i]); - - /* Check FDIR pointers and check and extract file names from DDRs */ - for (i=0; i<128; i++) - { - if (dest->files[i].fdr_ptr >= totphysrecs) - { - return IMGTOOLERR_CORRUPTIMAGE; - } - else if (dest->files[i].fdr_ptr) - { - reply = read_absolute_physrec(& l2_img->l1_img, dest->files[i].fdr_ptr, &fdr); - if (reply) - return IMGTOOLERR_READERROR; - - /* check and copy file name */ - if (check_fname(fdr.name)) - return IMGTOOLERR_CORRUPTIMAGE; - memcpy(dest->files[i].name, fdr.name, 10); - } - } - - /* Check catalog */ - for (i=0; i<127; i++) - { - if (((! dest->files[i].fdr_ptr) && dest->files[i+1].fdr_ptr) - || ((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, std::size(dest->files), sizeof(dest->files[0]), - cat_file_compare_qsort); - break; - } - } - - /* Set file count */ - for (i=0; (i<128) && (dest->files[i].fdr_ptr != 0); i++) - ; - dest->num_files = i; - - /* Set subdir count to 0 (subdirs are loaded elsewhere) */ - dest->num_subdirs = 0; - - return 0; -} - -/* - Read a directory catalog from disk image - - l2_img: image reference - DDR_AU: AU address of the VIB/DDR - dest: pointer to the destination buffer where the catalog should be written - - Return an error code if there was an error, 0 otherwise. -*/ -static int win_read_catalog(struct ti99_lvl2_imgref *l2_img, int DDR_AU, ti99_catalog *dest) -{ - win_vib_ddr ddr_buf; - UINT16BE fdir_buf[128]; - win_fdr fdr_buf; - int i; - int reply; - - - /* Read DDR record */ - reply = read_absolute_physrec(& l2_img->l1_img, DDR_AU*l2_img->AUformat.physrecsperAU, &ddr_buf); - if (reply) - return IMGTOOLERR_READERROR; - - /* sanity checks */ - if ((ddr_buf.num_files > 127) || (ddr_buf.num_subdirs > 114) || (get_UINT16BE(ddr_buf.fdir_AU) > l2_img->AUformat.totAUs)) - return IMGTOOLERR_CORRUPTIMAGE; - - /* set file count and subdir count */ - dest->num_files = ddr_buf.num_files; - dest->num_subdirs = ddr_buf.num_subdirs; - - /* Copy DDR info to catalog structure */ - for (i=0; isubdirs[i].dir_ptr = get_UINT16BE(ddr_buf.subdir_AU[i]); - - /* Read FDIR record */ - reply = read_absolute_physrec(& l2_img->l1_img, get_UINT16BE(ddr_buf.fdir_AU)*l2_img->AUformat.physrecsperAU, fdir_buf); - if (reply) - return IMGTOOLERR_READERROR; - - /* Copy FDIR info to catalog structure */ - for (i=0; inum_files; i++) - dest->files[i].fdr_ptr = get_UINT16BE(fdir_buf[i]); - - /* Check DDR pointers and check and extract file names from FDRs */ - for (i=0; inum_subdirs; i++) - { - if (dest->subdirs[i].dir_ptr >= l2_img->AUformat.totAUs) - { - return IMGTOOLERR_CORRUPTIMAGE; - } - else if (dest->subdirs[i].dir_ptr) - { - reply = read_absolute_physrec(& l2_img->l1_img, dest->subdirs[i].dir_ptr*l2_img->AUformat.physrecsperAU, &ddr_buf); - if (reply) - return IMGTOOLERR_READERROR; - - /* check and copy file name */ - if (check_fname(ddr_buf.name)) - return IMGTOOLERR_CORRUPTIMAGE; - memcpy(dest->subdirs[i].name, ddr_buf.name, 10); - } - } - - /* Check FDIR pointers and check and extract file names from FDRs */ - for (i=0; inum_files; i++) - { - if (dest->files[i].fdr_ptr >= l2_img->AUformat.totAUs) - { - return IMGTOOLERR_CORRUPTIMAGE; - } - else if (dest->files[i].fdr_ptr) - { - reply = read_absolute_physrec(& l2_img->l1_img, dest->files[i].fdr_ptr*l2_img->AUformat.physrecsperAU, &fdr_buf); - if (reply) - return IMGTOOLERR_READERROR; - - /* check and copy file name */ - if (check_fname(fdr_buf.name)) - return IMGTOOLERR_CORRUPTIMAGE; - memcpy(dest->files[i].name, fdr_buf.name, 10); - } - } - - /* Check catalog */ - - /* Check subdir order */ - for (i=0; inum_subdirs-1; i++) - { - if (((! dest->subdirs[i].dir_ptr) && dest->subdirs[i+1].dir_ptr) - || ((dest->subdirs[i].dir_ptr && dest->subdirs[i+1].dir_ptr) && (memcmp(dest->subdirs[i].name, dest->subdirs[i+1].name, 10) >= 0))) - { - /* if the subdir catalog is not sorted, we repair it */ - qsort(dest->subdirs, dest->num_subdirs, sizeof(dest->subdirs[0]), cat_dir_compare_qsort); - break; - } - } - - /* Fix subdir count */ - while (dest->num_subdirs && (dest->subdirs[dest->num_subdirs-1].dir_ptr == 0)) - dest->num_subdirs--; - - /* Check file order */ - for (i=0; inum_files-1; i++) - { - if (((! dest->files[i].fdr_ptr) && dest->files[i+1].fdr_ptr) - || ((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 file catalog is not sorted, we repair it */ - qsort(dest->files, dest->num_files, sizeof(dest->files[0]), cat_file_compare_qsort); - break; - } - } - - /* Fix file count */ - while (dest->num_files && (dest->files[dest->num_files-1].fdr_ptr == 0)) - dest->num_files--; - - return 0; -} - -/* - Search for a file path on a floppy image - - l2_img: image reference - fpath: path of the file to search - parent_ref_valid: set to true if either the file was found or the file was - not found but its parent dir was - parent_ref: reference to parent dir (0 for root) - out_is_dir: true if element is a directory - catalog_index: on output, index of file catalog entry (may be NULL) -*/ -static int dsk_find_catalog_entry(struct ti99_lvl2_imgref *l2_img, const char *fpath, int *parent_ref_valid, int *parent_ref, int *out_is_dir, int *catalog_index) -{ - int i; - const ti99_catalog *cur_catalog; - const char *element_start, *element_end; - int element_len; - char element[10]; - int is_dir = false; - - - cur_catalog = & l2_img->dsk.catalogs[0]; - if (parent_ref_valid) - (* parent_ref_valid) = false; - if (parent_ref) - *parent_ref = 0; - - element_start = fpath; - do - { - /* find next path element */ - element_end = strchr(element_start, '.'); - element_len = element_end ? (element_end - element_start) : strlen(element_start); - if ((element_len > 10) || (element_len == 0)) - return IMGTOOLERR_BADFILENAME; - /* last path element */ - if ((!element_end) && parent_ref_valid) - (* parent_ref_valid) = true; - - /* generate file name */ - memcpy(element, element_start, element_len); - memset(element+element_len, ' ', 10-element_len); - - /* search entry in subdirectories */ - for (i = 0; inum_subdirs; i++) - { - if (! memcmp(element, cur_catalog->subdirs[i].name, 10)) - { - is_dir = true; - break; - } - } - - /* if it failed, search entry in files */ - if (i == cur_catalog->num_subdirs) - { - for (i = 0; inum_files; i++) - { - if (! memcmp(element, cur_catalog->files[i].name, 10)) - { - is_dir = false; - break; - } - } - /* exit if not found */ - if (i == cur_catalog->num_files) - { - return IMGTOOLERR_FILENOTFOUND; - } - } - - /* iterate */ - if (element_end) - { - element_start = element_end+1; - - if (! is_dir) - /* this is not a directory */ - return IMGTOOLERR_BADFILENAME; - - /* initialize cur_catalog */ - cur_catalog = & l2_img->dsk.catalogs[i+1]; - if (parent_ref) - *parent_ref = i+1; - } - else - element_start = NULL; - } - while (element_start); - - if (out_is_dir) - *out_is_dir = is_dir; - - if (catalog_index) - *catalog_index = i; - - return 0; -} - -/* - Search for a file path on a harddisk image - - l2_img: image reference - fpath: path of the file to search - parent_ref_valid: set to true if either the file was found or the file was - not found but its parent dir was - parent_ddr_AU: parent DDR AU address (0 for root) - parent_catalog: catalog of parent dir (cannot be NULL) - out_is_dir: true if element is a directory - catalog_index: on output, index of file catalog entry (may be NULL) -*/ -static int win_find_catalog_entry(struct ti99_lvl2_imgref *l2_img, const char *fpath, - int *parent_ref_valid, int *parent_ddr_AU, ti99_catalog *parent_catalog, - int *out_is_dir, int *catalog_index) -{ - int i; - const char *element_start, *element_end; - int element_len; - char element[10]; - int is_dir = false; - int errorcode; - - if (parent_ref_valid) - (* parent_ref_valid) = false; - if (parent_ddr_AU) - *parent_ddr_AU = 0; - - errorcode = win_read_catalog(l2_img, 0, parent_catalog); - if (errorcode) - return errorcode; - - element_start = fpath; - do - { - /* find next path element */ - element_end = strchr(element_start, '.'); - element_len = element_end ? (element_end - element_start) : strlen(element_start); - if ((element_len > 10) || (element_len == 0)) - return IMGTOOLERR_BADFILENAME; - /* last path element */ - if ((!element_end) && parent_ref_valid) - (* parent_ref_valid) = true; - - /* generate file name */ - memcpy(element, element_start, element_len); - memset(element+element_len, ' ', 10-element_len); - - /* search entry in subdirectories */ - for (i = 0; inum_subdirs; i++) - { - if (! memcmp(element, parent_catalog->subdirs[i].name, 10)) - { - is_dir = true; - break; - } - } - - /* if it failed, search entry in files */ - if (i == parent_catalog->num_subdirs) - { - for (i = 0; inum_files; i++) - { - if (! memcmp(element, parent_catalog->files[i].name, 10)) - { - is_dir = false; - break; - } - } - /* exit if not found */ - if (i == parent_catalog->num_files) - { - return IMGTOOLERR_FILENOTFOUND; - } - } - - /* iterate */ - if (element_end) - { - element_start = element_end+1; - - if (! is_dir) - /* this is not a directory */ - return IMGTOOLERR_BADFILENAME; - - if (parent_ddr_AU) - *parent_ddr_AU = parent_catalog->subdirs[i].dir_ptr; - - errorcode = win_read_catalog(l2_img, parent_catalog->subdirs[i].dir_ptr, parent_catalog); - if (errorcode) - return errorcode; - } - else - element_start = NULL; - } - while (element_start); - - if (out_is_dir) - *out_is_dir = is_dir; - - if (catalog_index) - *catalog_index = i; - - return 0; -} - -/* - Allocate one AU on disk, for use as a fdr record - - l2_img: image reference - fdr_AU: on output, address of allocated AU -*/ -static int alloc_fdr_AU(struct ti99_lvl2_imgref *l2_img, unsigned *fdr_AU) -{ - int totAUs = l2_img->AUformat.totAUs; - int i; - - for (i=0; iabm[i >> 3] & (1 << (i & 7)))) - { - *fdr_AU = i; - l2_img->abm[i >> 3] |= 1 << (i & 7); - - return 0; - } - } - - return IMGTOOLERR_NOSPACE; -} - -static inline int get_dsk_fdr_cluster_baseAU(struct ti99_lvl2_imgref *l2_img, dsk_fdr *fdr, int cluster_index) -{ - int reply; - - /* read base AU/physrec for this cluster */ - reply = ((fdr->clusters[cluster_index][1] & 0xf) << 8) | fdr->clusters[cluster_index][0]; - /* convert to AU address */ - if (l2_img->AUformat.physrecsperAU <= 2) - reply /= l2_img->AUformat.physrecsperAU; - - return reply; -} - -static inline int get_dsk_fdr_cluster_baseaphysrec(struct ti99_lvl2_imgref *l2_img, dsk_fdr *fdr, int cluster_index) -{ - int reply; - - /* read base AU/physrec for this cluster */ - reply = ((fdr->clusters[cluster_index][1] & 0xf) << 8) | fdr->clusters[cluster_index][0]; - /* convert to physrec address */ - if (l2_img->AUformat.physrecsperAU > 2) - reply *= l2_img->AUformat.physrecsperAU; - - return reply; -} - -static inline int get_dsk_fdr_cluster_lastfphysrec(dsk_fdr *fdr, int cluster_index) -{ - return (fdr->clusters[cluster_index][2] << 4) | (fdr->clusters[cluster_index][1] >> 4); -} - -static inline void set_dsk_fdr_cluster_lastfphysrec(dsk_fdr *fdr, int cluster_index, int data) -{ - fdr->clusters[cluster_index][1] = (fdr->clusters[cluster_index][1] & 0x0f) | (data << 4); - fdr->clusters[cluster_index][2] = data >> 4; -} - -static inline void set_dsk_fdr_cluster(struct ti99_lvl2_imgref *l2_img, dsk_fdr *fdr, int cluster_index, int baseAU, int lastfphysrec) -{ - /* convert AU address to FDR value */ - if (l2_img->AUformat.physrecsperAU <= 2) - baseAU *= l2_img->AUformat.physrecsperAU; - - /* write cluster entry */ - fdr->clusters[cluster_index][0] = baseAU; - fdr->clusters[cluster_index][1] = ((baseAU >> 8) & 0x0f) | (lastfphysrec << 4); - fdr->clusters[cluster_index][2] = lastfphysrec >> 4; -} - -static inline unsigned get_win_fdr_fphysrecs(win_fdr *fdr) -{ - return (((unsigned) fdr->xinfo_MSB << 12) & 0xf0000) | get_UINT16BE(fdr->fphysrecs_LSW); -} - -static inline void set_win_fdr_fphysrecs(win_fdr *fdr, unsigned data) -{ - fdr->xinfo_MSB = (fdr->xinfo_MSB & 0x0f) | ((data >> 12) & 0xf0); - set_UINT16BE(&fdr->fphysrecs_LSW, data & 0xffff); -} - -static inline unsigned get_win_fdr_fixrecs(win_fdr *fdr) -{ - return (((unsigned) fdr->xinfo_MSB << 16) & 0xf0000) | get_UINT16LE(fdr->fixrecs_LSW); -} - -static inline void set_win_fdr_fixrecs(win_fdr *fdr, unsigned data) -{ - fdr->xinfo_MSB = (fdr->xinfo_MSB & 0xf0) | ((data >> 16) & 0x0f); - set_UINT16LE(&fdr->fixrecs_LSW, data & 0xffff); -} - -static inline unsigned get_win_fdr_prevsibFDR_aphysrec(struct ti99_lvl2_imgref *l2_img, win_fdr *fdr) -{ - unsigned prevsibFDR_AU = get_UINT16BE(fdr->prevsibFDR_AU); - - return prevsibFDR_AU - ? (prevsibFDR_AU * l2_img->AUformat.physrecsperAU + ((fdr->xinfo_LSB >> 4) & 0xf)) - : 0; -} - -static inline unsigned get_win_fdr_nextsibFDR_aphysrec(struct ti99_lvl2_imgref *l2_img, win_fdr *fdr) -{ - unsigned nextsibFDR_AU = get_UINT16BE(fdr->nextsibFDR_AU); - - return nextsibFDR_AU - ? (nextsibFDR_AU * l2_img->AUformat.physrecsperAU + (fdr->xinfo_LSB & 0xf)) - : 0; -} - -static inline unsigned get_win_fdr_cursibFDR_basefphysrec(win_fdr *fdr) -{ - return get_UINT16BE(fdr->prevsibFDR_AU) ? get_win_fdr_fphysrecs(fdr) : 0; -} - -/* - Advance to next sibling FDR -*/ -static int win_goto_next_sibFDR(ti99_lvl2_fileref_win *win_file) -{ - if (get_UINT16BE(win_file->curfdr.nextsibFDR_AU) == 0) - return IMGTOOLERR_UNEXPECTED; - - win_file->curfdr_aphysrec = get_win_fdr_nextsibFDR_aphysrec(win_file->l2_img, &win_file->curfdr); - if (read_absolute_physrec(& win_file->l2_img->l1_img, win_file->curfdr_aphysrec, &win_file->curfdr)) - return IMGTOOLERR_READERROR; - - return 0; -} - -/* - Back to previous sibling FDR -*/ -static int win_goto_prev_sibFDR(ti99_lvl2_fileref_win *win_file) -{ - if (get_UINT16BE(win_file->curfdr.prevsibFDR_AU) == 0) - return IMGTOOLERR_UNEXPECTED; - - win_file->curfdr_aphysrec = get_win_fdr_prevsibFDR_aphysrec(win_file->l2_img, &win_file->curfdr); - if (read_absolute_physrec(& win_file->l2_img->l1_img, win_file->curfdr_aphysrec, &win_file->curfdr)) - return IMGTOOLERR_READERROR; - - return 0; -} - -/* - Append a new sibling FDR at the end of the sibling FDR list, and open it. - - You must have gone to the end of the list. -*/ -static int win_alloc_sibFDR(ti99_lvl2_fileref_win *win_file) -{ - unsigned oldfdr_AU, oldfdr_physrecinAU; - unsigned newfdr_AU, newfdr_physrecinAU; - int allocated = false; - int errorcode; - unsigned cursibFDR_basefphysrec; - - if (get_UINT16BE(win_file->curfdr.nextsibFDR_AU)) - return IMGTOOLERR_UNEXPECTED; - - oldfdr_AU = win_file->curfdr_aphysrec / win_file->l2_img->AUformat.physrecsperAU; - oldfdr_physrecinAU = win_file->curfdr_aphysrec % win_file->l2_img->AUformat.physrecsperAU; - - if (oldfdr_physrecinAU != (win_file->l2_img->AUformat.physrecsperAU - 1)) - { /* current AU is not full */ - newfdr_AU = oldfdr_AU; - newfdr_physrecinAU = oldfdr_physrecinAU + 1; - } - else - { /* current AU is full: allocate another */ - errorcode = alloc_fdr_AU(win_file->l2_img, &newfdr_AU); - if (errorcode) - return errorcode; - newfdr_physrecinAU = 0; - allocated = true; - } - - set_UINT16BE(&win_file->curfdr.nextsibFDR_AU, newfdr_AU); - win_file->curfdr.xinfo_LSB = (win_file->curfdr.xinfo_LSB & 0xf0) | newfdr_physrecinAU; - - /* save current sibling FDR */ - if (write_absolute_physrec(& win_file->l2_img->l1_img, win_file->curfdr_aphysrec, &win_file->curfdr)) - { - /* clear pointer */ - set_UINT16BE(&win_file->curfdr.nextsibFDR_AU, 0); - win_file->curfdr.xinfo_LSB = win_file->curfdr.xinfo_LSB & 0xf0; - if (allocated) - /* free AU */ - win_file->l2_img->abm[newfdr_AU >> 3] |= 1 << (newfdr_AU & 7); - return IMGTOOLERR_WRITEERROR; - } - - /* now update in-memory structure to describe new sibling FDR */ - cursibFDR_basefphysrec = get_win_fdr_cursibFDR_basefphysrec(&win_file->curfdr) - + get_UINT16BE(win_file->curfdr.sibFDR_AUlen) * win_file->l2_img->AUformat.physrecsperAU; - - set_UINT16BE(&win_file->curfdr.nextsibFDR_AU, 0); - set_UINT16BE(&win_file->curfdr.prevsibFDR_AU, oldfdr_AU); - win_file->curfdr.xinfo_LSB = oldfdr_physrecinAU << 4; - - win_file->curfdr_aphysrec = newfdr_AU * win_file->l2_img->AUformat.physrecsperAU + newfdr_physrecinAU; - - set_win_fdr_fphysrecs(&win_file->curfdr, cursibFDR_basefphysrec); - set_UINT16BE(&win_file->curfdr.sibFDR_AUlen, 0); - memset(win_file->curfdr.clusters, 0, sizeof(win_file->curfdr.clusters)); - - return 0; -} - -/* - Extend a file with nb_alloc_physrecs extra physrecs - - dsk_file: file reference - nb_alloc_physrecs: number of physical records to allocate -*/ -static int dsk_alloc_file_physrecs(ti99_lvl2_fileref_dsk *dsk_file, int nb_alloc_physrecs) -{ - int totAUs = dsk_file->l2_img->AUformat.totAUs; - int free_physrecs; - int fphysrecs; - int i; - int cluster_index; - int last_sec, p_last_sec = 0; - int cur_block_seclen; - int cluster_baseAU, cluster_AUlen; - int first_best_block_baseAU = 0, first_best_block_seclen; - int second_best_block_baseAU = 0, second_best_block_seclen; - int search_start; - - /* compute free space */ - free_physrecs = 0; - for (i=0; il2_img->abm[i >> 3] & (1 << (i & 7)))) - free_physrecs += dsk_file->l2_img->AUformat.physrecsperAU; - } - - /* check we have enough free space */ - if (free_physrecs < nb_alloc_physrecs) - return IMGTOOLERR_NOSPACE; - - /* current number of data physrecs in file */ - fphysrecs = get_UINT16BE(dsk_file->fdr.fphysrecs); - - if (fphysrecs == 0) - { /* cluster array must be empty */ - cluster_index = 0; - } - else - { /* try to extend last block */ - last_sec = -1; - for (cluster_index=0; cluster_index<76; cluster_index++) - { - p_last_sec = last_sec; - last_sec = get_dsk_fdr_cluster_lastfphysrec(&dsk_file->fdr, cluster_index); - if (last_sec >= (fphysrecs-1)) - break; - } - if (cluster_index == 76) - /* that sucks */ - return IMGTOOLERR_CORRUPTIMAGE; - - if (last_sec > (fphysrecs-1)) - { /* some extra space has already been allocated */ - cur_block_seclen = last_sec - (fphysrecs-1); - if (cur_block_seclen > nb_alloc_physrecs) - cur_block_seclen = nb_alloc_physrecs; - - fphysrecs += cur_block_seclen; - set_UINT16BE(& dsk_file->fdr.fphysrecs, fphysrecs); - nb_alloc_physrecs -= cur_block_seclen; - if (! nb_alloc_physrecs) - return 0; /* done */ - } - - /* round up to next AU boundary */ - last_sec = last_sec + dsk_file->l2_img->AUformat.physrecsperAU - (last_sec % dsk_file->l2_img->AUformat.physrecsperAU) - 1; - - if (last_sec > (fphysrecs-1)) - { /* some extra space has already been allocated */ - cur_block_seclen = last_sec - (fphysrecs-1); - if (cur_block_seclen > nb_alloc_physrecs) - cur_block_seclen = nb_alloc_physrecs; - - fphysrecs += cur_block_seclen; - set_UINT16BE(& dsk_file->fdr.fphysrecs, fphysrecs); - set_dsk_fdr_cluster_lastfphysrec(&dsk_file->fdr, cluster_index, fphysrecs-1); - nb_alloc_physrecs -= cur_block_seclen; - if (! nb_alloc_physrecs) - return 0; /* done */ - } - - /* read base AU address for this cluster */ - cluster_baseAU = get_dsk_fdr_cluster_baseAU(dsk_file->l2_img, &dsk_file->fdr, cluster_index); - /* point past cluster end */ - cluster_baseAU += (last_sec-p_last_sec/*+file->l2_img->AUformat.physrecsperAU-1*/) / dsk_file->l2_img->AUformat.physrecsperAU; - /* count free physrecs after last block */ - cur_block_seclen = 0; - for (i=cluster_baseAU; (! (dsk_file->l2_img->abm[i >> 3] & (1 << (i & 7)))) && (cur_block_seclen < nb_alloc_physrecs) && (i < totAUs); i++) - cur_block_seclen += dsk_file->l2_img->AUformat.physrecsperAU; - if (cur_block_seclen) - { /* extend last block */ - if (cur_block_seclen > nb_alloc_physrecs) - cur_block_seclen = nb_alloc_physrecs; - - fphysrecs += cur_block_seclen; - set_UINT16BE(& dsk_file->fdr.fphysrecs, fphysrecs); - last_sec += cur_block_seclen; - nb_alloc_physrecs -= cur_block_seclen; - set_dsk_fdr_cluster_lastfphysrec(&dsk_file->fdr, cluster_index, last_sec); - cluster_AUlen = (cur_block_seclen + dsk_file->l2_img->AUformat.physrecsperAU - 1) / dsk_file->l2_img->AUformat.physrecsperAU; - for (i=0; il2_img->abm[(i+cluster_baseAU) >> 3] |= 1 << ((i+cluster_baseAU) & 7); - if (! nb_alloc_physrecs) - return 0; /* done */ - } - cluster_index++; - if (cluster_index == 76) - /* that sucks */ - return IMGTOOLERR_NOSPACE; - } - - search_start = dsk_file->l2_img->data_offset; /* initially, search for free space only in data space */ - while (nb_alloc_physrecs) - { - /* find smallest data block at least nb_alloc_physrecs in length, and largest data block less than nb_alloc_physrecs in length */ - first_best_block_seclen = INT_MAX; - second_best_block_seclen = 0; - for (i=search_start; il2_img->abm[i >> 3] & (1 << (i & 7)))) - { /* found one free block */ - /* compute its length */ - cluster_baseAU = i; - cur_block_seclen = 0; - while ((il2_img->abm[i >> 3] & (1 << (i & 7))))) - { - cur_block_seclen += dsk_file->l2_img->AUformat.physrecsperAU; - i++; - } - /* compare to previous best and second-best blocks */ - if ((cur_block_seclen < first_best_block_seclen) && (cur_block_seclen >= nb_alloc_physrecs)) - { - first_best_block_baseAU = cluster_baseAU; - first_best_block_seclen = cur_block_seclen; - if (cur_block_seclen == nb_alloc_physrecs) - /* no need to search further */ - break; - } - else if ((cur_block_seclen > second_best_block_seclen) && (cur_block_seclen < nb_alloc_physrecs)) - { - second_best_block_baseAU = cluster_baseAU; - second_best_block_seclen = cur_block_seclen; - } - } - } - - if (first_best_block_seclen != INT_MAX) - { /* found one contiguous block which can hold it all */ - fphysrecs += nb_alloc_physrecs; - set_UINT16BE(& dsk_file->fdr.fphysrecs, fphysrecs); - - set_dsk_fdr_cluster(dsk_file->l2_img, &dsk_file->fdr, cluster_index, first_best_block_baseAU, fphysrecs-1); - cluster_AUlen = (nb_alloc_physrecs + dsk_file->l2_img->AUformat.physrecsperAU - 1) / dsk_file->l2_img->AUformat.physrecsperAU; - for (i=0; il2_img->abm[(i+first_best_block_baseAU) >> 3] |= 1 << ((i+first_best_block_baseAU) & 7); - - nb_alloc_physrecs = 0; - } - else if (second_best_block_seclen != 0) - { /* jeez, we need to fragment it. We use the largest smaller block to limit fragmentation. */ - fphysrecs += second_best_block_seclen; - set_UINT16BE(& dsk_file->fdr.fphysrecs, fphysrecs); - - set_dsk_fdr_cluster(dsk_file->l2_img, &dsk_file->fdr, cluster_index, second_best_block_baseAU, fphysrecs-1); - cluster_AUlen = (second_best_block_seclen + dsk_file->l2_img->AUformat.physrecsperAU - 1) / dsk_file->l2_img->AUformat.physrecsperAU; - for (i=0; il2_img->abm[(i+second_best_block_baseAU) >> 3] |= 1 << ((i+second_best_block_baseAU) & 7); - - nb_alloc_physrecs -= second_best_block_seclen; - - cluster_index++; - if (cluster_index == 76) - /* that sucks */ - return IMGTOOLERR_NOSPACE; - } - else if (search_start != 0) - { /* we did not find any free physrec in the data section of the disk */ - search_start = 0; /* time to fall back to fdr space */ - } - else - return IMGTOOLERR_NOSPACE; /* This should never happen, as we pre-check that there is enough free space */ - } - - return 0; -} - -/* - Extend a file with nb_alloc_physrecs extra physrecs - - win_file: file reference - nb_alloc_physrecs: number of physical records to allocate -*/ -static int win_alloc_file_physrecs(ti99_lvl2_fileref_win *win_file, int nb_alloc_physrecs) -{ - int totAUs = win_file->l2_img->AUformat.totAUs; - int free_physrecs; - int fphysrecs; - int i; - int cluster_index; - int num_fphysrec; - int cur_block_seclen; - int cluster_baseAU, cluster_AUlen; - int first_best_block_baseAU = 0, first_best_block_seclen; - int second_best_block_baseAU = 0, second_best_block_seclen; - int search_start; - int errorcode; - - /* compute free space */ - free_physrecs = 0; - for (i=0; il2_img->abm[i >> 3] & (1 << (i & 7)))) - free_physrecs += win_file->l2_img->AUformat.physrecsperAU; - } - - /* check we have enough free space */ - if (free_physrecs < nb_alloc_physrecs) - return IMGTOOLERR_NOSPACE; - - /* move to last sibling non-empty FDR */ - while ((get_UINT16BE(win_file->curfdr.nextsibFDR_AU) != 0) && - (get_UINT16BE(win_file->curfdr.clusters[53][0]) != 0)) - { - errorcode = win_goto_next_sibFDR(win_file); - if (errorcode) - return errorcode; - } - if ((get_UINT16BE(win_file->curfdr.clusters[0][0]) == 0) && (get_UINT16BE(win_file->curfdr.prevsibFDR_AU) != 0)) - { /* this is annoying: we have found a sibling FDR filled with 0s: rewind - to last non-empty sibling if applicable */ - errorcode = win_goto_prev_sibFDR(win_file); - if (errorcode) - return errorcode; - } - - /* current number of data physrecs in file */ - fphysrecs = win_file->fphysrecs; - - /* current number of allocated physrecs */ - num_fphysrec = get_win_fdr_cursibFDR_basefphysrec(&win_file->curfdr) - + get_UINT16BE(win_file->curfdr.sibFDR_AUlen) * win_file->l2_img->AUformat.physrecsperAU; - - if (num_fphysrec > fphysrecs) - { /* some extra space has already been allocated */ - cur_block_seclen = num_fphysrec - fphysrecs; - if (cur_block_seclen > nb_alloc_physrecs) - cur_block_seclen = nb_alloc_physrecs; - - fphysrecs += cur_block_seclen; - win_file->fphysrecs = fphysrecs; - /* TODO: update eldest FDR fphysrecs field */ - /*set_win_fdr_fphysrecs(& win_file->rootfdr.fphysrecs, fphysrecs);*/ - nb_alloc_physrecs -= cur_block_seclen; - if (! nb_alloc_physrecs) - return 0; /* done */ - } - - /* find last non-empty cluster */ - for (cluster_index=0; (cluster_index<54) && (get_UINT16BE(win_file->curfdr.clusters[cluster_index][0]) != 0); cluster_index++) - ; - /* if we are dealing with an empty file, we will have (cluster_index == 0)... */ - if (cluster_index != 0) - { - cluster_index--; - /* try to extend last cluster */ - /* point past cluster end */ - cluster_baseAU = get_UINT16BE(win_file->curfdr.clusters[cluster_index][1]) + 1; - /* count free physrecs after last block */ - cur_block_seclen = 0; - for (i=cluster_baseAU; (! (win_file->l2_img->abm[i >> 3] & (1 << (i & 7)))) && (cur_block_seclen < nb_alloc_physrecs) && (i < totAUs); i++) - cur_block_seclen += win_file->l2_img->AUformat.physrecsperAU; - if (cur_block_seclen) - { /* extend last block */ - if (cur_block_seclen > nb_alloc_physrecs) - cur_block_seclen = nb_alloc_physrecs; - - fphysrecs += cur_block_seclen; - cluster_AUlen = (cur_block_seclen + win_file->l2_img->AUformat.physrecsperAU - 1) / win_file->l2_img->AUformat.physrecsperAU; - win_file->fphysrecs = fphysrecs; - /* TODO: update eldest FDR fphysrecs field */ - /*set_win_fdr_fphysrecs(& win_file->rootfdr.fphysrecs, fphysrecs);*/ - set_UINT16BE(&win_file->curfdr.sibFDR_AUlen, - get_UINT16BE(win_file->curfdr.sibFDR_AUlen)+cluster_AUlen); - set_UINT16BE(&win_file->curfdr.clusters[cluster_index][1], - get_UINT16BE(win_file->curfdr.clusters[cluster_index][1])+cluster_AUlen); - for (i=0; il2_img->abm[(i+cluster_baseAU) >> 3] |= 1 << ((i+cluster_baseAU) & 7); - nb_alloc_physrecs -= cur_block_seclen; - if (! nb_alloc_physrecs) - return 0; /* done */ - } - /* now point to first free entry in cluster table */ - cluster_index++; - } - - search_start = win_file->l2_img->data_offset; /* initially, search for free space only in data space */ - while (nb_alloc_physrecs) - { - /* find smallest data block at least nb_alloc_physrecs in length, and largest data block less than nb_alloc_physrecs in length */ - first_best_block_seclen = INT_MAX; - second_best_block_seclen = 0; - for (i=search_start; il2_img->abm[i >> 3] & (1 << (i & 7)))) - { /* found one free block */ - /* compute its length */ - cluster_baseAU = i; - cur_block_seclen = 0; - while ((il2_img->abm[i >> 3] & (1 << (i & 7))))) - { - cur_block_seclen += win_file->l2_img->AUformat.physrecsperAU; - i++; - } - /* compare to previous best and second-best blocks */ - if ((cur_block_seclen < first_best_block_seclen) && (cur_block_seclen >= nb_alloc_physrecs)) - { - first_best_block_baseAU = cluster_baseAU; - first_best_block_seclen = cur_block_seclen; - if (cur_block_seclen == nb_alloc_physrecs) - /* no need to search further */ - break; - } - else if ((cur_block_seclen > second_best_block_seclen) && (cur_block_seclen < nb_alloc_physrecs)) - { - second_best_block_baseAU = cluster_baseAU; - second_best_block_seclen = cur_block_seclen; - } - } - } - - if ((first_best_block_seclen != INT_MAX) || (second_best_block_seclen != 0)) - { - if (cluster_index == 54) - { - /* end of cluster list: go to next sibling FDR */ - if (write_absolute_physrec(& win_file->l2_img->l1_img, win_file->curfdr_aphysrec, &win_file->curfdr)) - return IMGTOOLERR_WRITEERROR; - if (get_UINT16BE(win_file->curfdr.nextsibFDR_AU) != 0) - { /* read next sibling FDR */ - errorcode = win_goto_next_sibFDR(win_file); - if (errorcode) - return errorcode; - } - else - { /* allocate new sibling FDR */ - errorcode = win_alloc_sibFDR(win_file); - if (errorcode) - return errorcode; - } - cluster_index = 0; - } - } - - if (first_best_block_seclen != INT_MAX) - { /* found one contiguous block which can hold it all */ - fphysrecs += nb_alloc_physrecs; - cluster_AUlen = (nb_alloc_physrecs + win_file->l2_img->AUformat.physrecsperAU - 1) / win_file->l2_img->AUformat.physrecsperAU; - win_file->fphysrecs = fphysrecs; - /* TODO: update eldest FDR fphysrecs field */ - /*set_win_fdr_fphysrecs(& win_file->rootfdr.fphysrecs, fphysrecs);*/ - set_UINT16BE(&win_file->curfdr.sibFDR_AUlen, - get_UINT16BE(win_file->curfdr.sibFDR_AUlen)+cluster_AUlen); - set_UINT16BE(&win_file->curfdr.clusters[cluster_index][0], first_best_block_baseAU); - set_UINT16BE(&win_file->curfdr.clusters[cluster_index][1], - first_best_block_baseAU+cluster_AUlen-1); - - for (i=0; il2_img->abm[(i+first_best_block_baseAU) >> 3] |= 1 << ((i+first_best_block_baseAU) & 7); - - nb_alloc_physrecs = 0; - } - else if (second_best_block_seclen != 0) - { /* jeez, we need to fragment it. We use the largest smaller block to limit fragmentation. */ - fphysrecs += second_best_block_seclen; - cluster_AUlen = (second_best_block_seclen + win_file->l2_img->AUformat.physrecsperAU - 1) / win_file->l2_img->AUformat.physrecsperAU; - win_file->fphysrecs = fphysrecs; - /* TODO: update eldest FDR fphysrecs field */ - /*set_win_fdr_fphysrecs(& win_file->rootfdr.fphysrecs, fphysrecs);*/ - set_UINT16BE(&win_file->curfdr.sibFDR_AUlen, - get_UINT16BE(win_file->curfdr.sibFDR_AUlen)+cluster_AUlen); - set_UINT16BE(&win_file->curfdr.clusters[cluster_index][0], second_best_block_baseAU); - set_UINT16BE(&win_file->curfdr.clusters[cluster_index][1], - second_best_block_baseAU+cluster_AUlen-1); - - for (i=0; il2_img->abm[(i+second_best_block_baseAU) >> 3] |= 1 << ((i+second_best_block_baseAU) & 7); - - nb_alloc_physrecs -= second_best_block_seclen; - - /* now point to first free entry in cluster table */ - cluster_index++; - } - else if (search_start != 0) - { /* we did not find any free physrec in the data section of the disk */ - search_start = 0; /* time to fall back to fdr space */ - } - else - return IMGTOOLERR_NOSPACE; /* This should never happen, as we pre-check that there is enough free space */ - } - - return 0; -} - -/* - Allocate a new (empty) file -*/ -static int new_file_lvl2_dsk(struct ti99_lvl2_imgref *l2_img, int parent_ref, char filename[10], struct ti99_lvl2_fileref *l2_file) -{ - ti99_catalog *catalog = &l2_img->dsk.catalogs[parent_ref]; - unsigned fdr_AU, fdr_aphysrec; - int catalog_index, i; - int reply = 0; - int errorcode; - - - if (catalog->num_files >= 127) - /* if num_files == 128, catalog is full */ - /* if num_files == 127, catalog is not full, but we don't want to write - a 128th entry for compatibility with some existing DSRs that detect the - end of the FDIR array with a 0 entry (and do not check that the index - has not reached 128) */ - return IMGTOOLERR_NOSPACE; - - /* find insertion point in catalog */ - for (i=0; (i < catalog->num_files) && ((reply = memcmp(catalog->files[i].name, filename, 10)) < 0); i++) - ; - - if ((inum_files) && (reply == 0)) - /* file already exists */ - return IMGTOOLERR_BADFILENAME; - else - { - /* otherwise insert new entry */ - catalog_index = i; - errorcode = alloc_fdr_AU(l2_img, &fdr_AU); - if (errorcode) - return errorcode; - fdr_aphysrec = fdr_AU * l2_img->AUformat.physrecsperAU; - - /* shift catalog entries until the insertion point */ - for (i=catalog->num_files; i>catalog_index; i--) - catalog->files[i] = catalog->files[i-1]; - - /* write new catalog entry */ - catalog->files[catalog_index].fdr_ptr = fdr_aphysrec; - memcpy(catalog->files[catalog_index].name, filename, 10); - - /* update catalog len */ - catalog->num_files++; - } - - /* set up file handle */ - l2_file->type = L2F_DSK; - l2_file->dsk.l2_img = l2_img; - l2_file->dsk.fdr_aphysrec = fdr_aphysrec; - memset(&l2_file->dsk.fdr, 0, sizeof(l2_file->dsk.fdr)); - memcpy(l2_file->dsk.fdr.name, filename, 10); - - return 0; -} - -/* - Allocate a new (empty) file -*/ -static int new_file_lvl2_win(struct ti99_lvl2_imgref *l2_img, ti99_catalog *parent_catalog, char filename[10], struct ti99_lvl2_fileref *l2_file) -{ - unsigned fdr_AU; - int catalog_index, i; - int reply = 0; - int errorcode; - - - if (parent_catalog->num_files >= 127) - /* if num_files == 127, catalog is full */ - return IMGTOOLERR_NOSPACE; - - /* find insertion point in catalog */ - for (i=0; (i < parent_catalog->num_files) && ((reply = memcmp(parent_catalog->files[i].name, filename, 10)) < 0); i++) - ; - - if ((inum_files) && (reply == 0)) - /* file already exists */ - return IMGTOOLERR_BADFILENAME; - else - { - /* otherwise insert new entry */ - catalog_index = i; - errorcode = alloc_fdr_AU(l2_img, &fdr_AU); - if (errorcode) - return errorcode; - - /* shift catalog entries until the insertion point */ - for (i=parent_catalog->num_files; i>catalog_index; i--) - parent_catalog->files[i] = parent_catalog->files[i-1]; - - /* write new catalog entry */ - parent_catalog->files[catalog_index].fdr_ptr = fdr_AU; - memcpy(parent_catalog->files[catalog_index].name, filename, 10); - - /* update catalog len */ - parent_catalog->num_files++; - } - - /* set up file handle */ - l2_file->type = L2F_WIN; - l2_file->win.l2_img = l2_img; - l2_file->win.fphysrecs = 0; - l2_file->win.eldestfdr_aphysrec = fdr_AU * l2_img->AUformat.physrecsperAU; - l2_file->win.curfdr_aphysrec = l2_file->win.eldestfdr_aphysrec; - memset(&l2_file->win.curfdr, 0, sizeof(l2_file->win.curfdr)); - memcpy(l2_file->win.curfdr.name, filename, 10); - - return 0; -} - -/* - Allocate a new (empty) file -*/ -static int new_file_lvl2_tifiles(imgtool::stream &file_handle, struct ti99_lvl2_fileref *l2_file) -{ - /* set up file handle */ - l2_file->type = L2F_TIFILES; - l2_file->tifiles.file_handle = &file_handle; - memset(&l2_file->tifiles.hdr, 0, sizeof(l2_file->tifiles.hdr)); - l2_file->tifiles.hdr.tifiles[0] = '\7'; - l2_file->tifiles.hdr.tifiles[1] = 'T'; - l2_file->tifiles.hdr.tifiles[2] = 'I'; - l2_file->tifiles.hdr.tifiles[3] = 'F'; - l2_file->tifiles.hdr.tifiles[4] = 'I'; - l2_file->tifiles.hdr.tifiles[5] = 'L'; - l2_file->tifiles.hdr.tifiles[6] = 'E'; - l2_file->tifiles.hdr.tifiles[7] = 'S'; - - return 0; -} - -/* - Open an existing file on a floppy image - - l2_img: level 2 image the file is located on - fpath: access path to the file - file: set up if open is successful -*/ -static int open_file_lvl2_dsk(struct ti99_lvl2_imgref *l2_img, const char *fpath, struct ti99_lvl2_fileref *l2_file) -{ - int parent_ref, is_dir, catalog_index; - int reply; - - - reply = dsk_find_catalog_entry(l2_img, fpath, NULL, &parent_ref, &is_dir, &catalog_index); - if (reply) - return reply; - - if (is_dir) - /* this is not a file */ - return IMGTOOLERR_BADFILENAME; - - l2_file->type = L2F_DSK; - l2_file->dsk.l2_img = l2_img; - l2_file->dsk.fdr_aphysrec = l2_img->dsk.catalogs[parent_ref].files[catalog_index].fdr_ptr; - if (read_absolute_physrec(& l2_img->l1_img, l2_file->dsk.fdr_aphysrec, &l2_file->dsk.fdr)) - return IMGTOOLERR_READERROR; - - return 0; -} - -/* - Open an existing file on a harddisk image - - l2_img: level 2 image the file is located on - fpath: access path to the file - file: set up if open is successful -*/ -static int open_file_lvl2_win(struct ti99_lvl2_imgref *l2_img, const char *fpath, struct ti99_lvl2_fileref *l2_file) -{ - int parent_ref, is_dir, catalog_index; - ti99_catalog catalog; - int reply; - - reply = win_find_catalog_entry(l2_img, fpath, NULL, &parent_ref, &catalog, &is_dir, &catalog_index); - if (reply) - return reply; - - if (is_dir) - /* this is not a file */ - return IMGTOOLERR_BADFILENAME; - - l2_file->type = L2F_WIN; - l2_file->win.l2_img = l2_img; - l2_file->win.eldestfdr_aphysrec = catalog.files[catalog_index].fdr_ptr * l2_img->AUformat.physrecsperAU; - l2_file->win.curfdr_aphysrec = l2_file->win.eldestfdr_aphysrec; - if (read_absolute_physrec(& l2_img->l1_img, l2_file->win.curfdr_aphysrec, &l2_file->win.curfdr)) - return IMGTOOLERR_READERROR; - l2_file->win.fphysrecs = get_win_fdr_fphysrecs(&l2_file->win.curfdr); - - /* check integrity of FDR sibling chain */ - /* 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 */ - if (get_UINT16BE(l2_file->win.curfdr.prevsibFDR_AU) != 0) - return IMGTOOLERR_CORRUPTIMAGE; - - { - int i, pastendoflist_flag; - unsigned cur_fphysrec, sibFDR_AUlen; - win_fdr *cur_fdr, fdr_buf; - unsigned curfdr_aphysrec, prevfdr_aphysrec; - - cur_fphysrec = 0; - pastendoflist_flag = 0; - cur_fdr = &l2_file->win.curfdr; - curfdr_aphysrec = l2_file->win.eldestfdr_aphysrec; - - while (1) - { - sibFDR_AUlen = 0; - i=0; - if (! pastendoflist_flag) - { - /* compute number of allocated AUs and check number of AUs */ - for (; i<54; i++) - { - if (get_UINT16BE(cur_fdr->clusters[i][0]) == 0) - { - pastendoflist_flag = true; - break; - } - sibFDR_AUlen += get_UINT16BE(cur_fdr->clusters[i][1]) - - get_UINT16BE(cur_fdr->clusters[i][0]) - + 1; - } - } - /* clear remainder of cluster table */ - for (; i<54; i++) - { -#if 0 - set_UINT16BE(&cur_fdr->clusters[i][0], 0); - set_UINT16BE(&cur_fdr->clusters[i][1], 0); -#endif - if ((get_UINT16BE(cur_fdr->clusters[i][0]) != 0) || (get_UINT16BE(cur_fdr->clusters[i][1]) != 0)) - return IMGTOOLERR_CORRUPTIMAGE; - } - - /* check sibFDR_AUlen field */ - if (get_UINT16BE(cur_fdr->sibFDR_AUlen) != sibFDR_AUlen) - return IMGTOOLERR_CORRUPTIMAGE; - - /* update current file physrec position to point to end of sibling FDR */ - cur_fphysrec += sibFDR_AUlen * l2_file->win.l2_img->AUformat.physrecsperAU; - - /* exit loop if end of sibling chain */ - if (! get_UINT16BE(cur_fdr->nextsibFDR_AU)) - break; - - /* otherwise read next FDR */ - if (get_UINT16BE(cur_fdr->nextsibFDR_AU) >= l2_file->win.l2_img->AUformat.totAUs) - return IMGTOOLERR_CORRUPTIMAGE; - - prevfdr_aphysrec = curfdr_aphysrec; - curfdr_aphysrec = get_win_fdr_nextsibFDR_aphysrec(l2_file->win.l2_img, cur_fdr); - if (read_absolute_physrec(& l2_file->win.l2_img->l1_img, curfdr_aphysrec, &fdr_buf)) - return IMGTOOLERR_READERROR; - cur_fdr = &fdr_buf; - - /* check that back chaining is consistent with forward chaining */ - if (get_win_fdr_prevsibFDR_aphysrec(l2_file->win.l2_img, &fdr_buf) != prevfdr_aphysrec) - return IMGTOOLERR_CORRUPTIMAGE; - /* check fphysrecs field */ - if (get_win_fdr_fphysrecs(&fdr_buf) != cur_fphysrec) - return IMGTOOLERR_CORRUPTIMAGE; - - /* check consistency of informative fields (name, record format, flags, etc) */ - if (memcmp(fdr_buf.name, l2_file->win.curfdr.name, 10) - || (get_UINT16BE(fdr_buf.xreclen) != get_UINT16BE(l2_file->win.curfdr.xreclen)) - || (fdr_buf.flags != l2_file->win.curfdr.flags) - || (fdr_buf.recsperphysrec != l2_file->win.curfdr.recsperphysrec) - || (fdr_buf.eof != l2_file->win.curfdr.eof) - || (fdr_buf.reclen != l2_file->win.curfdr.reclen) - || (get_UINT16LE(fdr_buf.fixrecs_LSW) != get_UINT16LE(l2_file->win.curfdr.fixrecs_LSW)) - || memcmp(&fdr_buf.creation, &l2_file->win.curfdr.creation, 4) - || memcmp(&fdr_buf.update, &l2_file->win.curfdr.update, 4) - /*|| memcmp(fdr_buf.id, l2_file->win.curfdr.id, 2)*/ - || (get_UINT16BE(fdr_buf.parent_FDIR_AU) != get_UINT16BE(l2_file->win.curfdr.parent_FDIR_AU)) - || ((fdr_buf.xinfo_MSB & 0xf) != (l2_file->win.curfdr.xinfo_MSB & 0xf))) - return IMGTOOLERR_CORRUPTIMAGE; - } - if (cur_fphysrec < l2_file->win.fphysrecs) - return IMGTOOLERR_CORRUPTIMAGE; - } - - return 0; -} - -/* - Open an existing file in TIFILES format -*/ -static int open_file_lvl2_tifiles(imgtool::stream &file_handle, struct ti99_lvl2_fileref *l2_file) -{ - /* set up file handle */ - l2_file->type = L2F_TIFILES; - l2_file->tifiles.file_handle = &file_handle; - - /* seek to header */ - if (l2_file->tifiles.file_handle->seek(0, SEEK_SET)) - return IMGTOOLERR_READERROR; - /* read it */ - if (l2_file->tifiles.file_handle->read(&l2_file->tifiles.hdr, sizeof(l2_file->tifiles.hdr)) != sizeof(l2_file->tifiles.hdr)) - return IMGTOOLERR_READERROR; - - return 0; -} - -/* - compute the aphysrec address for a given file physical record (fphysrec) - - l2_img: image where the file is located -*/ -static int dsk_fphysrec_to_aphysrec(ti99_lvl2_fileref_dsk *dsk_file, unsigned fphysrec, unsigned *aphysrec) -{ - int cluster_index; - int cluster_firstfphysrec, cluster_lastfphysrec; - int cluster_baseaphysrec; - - - /* check parameter */ - if (fphysrec >= get_UINT16BE(dsk_file->fdr.fphysrecs)) - return IMGTOOLERR_UNEXPECTED; - - - /* search for the cluster in the data chain pointers array */ - cluster_firstfphysrec = 0; - for (cluster_index=0; cluster_index<76; cluster_index++) - { - /* read curent file block table entry */ - cluster_lastfphysrec = get_dsk_fdr_cluster_lastfphysrec(&dsk_file->fdr, cluster_index); - if (cluster_lastfphysrec >= fphysrec) - break; - cluster_firstfphysrec = cluster_lastfphysrec+1; - } - if (cluster_index == 76) - /* if not found, the file is corrupt */ - return IMGTOOLERR_CORRUPTIMAGE; - - /* read base aphysrec address for this cluster */ - cluster_baseaphysrec = get_dsk_fdr_cluster_baseaphysrec(dsk_file->l2_img, &dsk_file->fdr, cluster_index); - /* return absolute physrec address */ - *aphysrec = cluster_baseaphysrec + (fphysrec - cluster_firstfphysrec); - return 0; -} - -/* - compute the aphysrec address for a given file physical record (fphysrec) - - l2_img: image where the file is located -*/ -static int win_fphysrec_to_aphysrec(ti99_lvl2_fileref_win *win_file, unsigned fphysrec, unsigned *aphysrec) -{ - int cluster_index; - int cluster_firstfphysrec, cluster_lastfphysrec; - int cluster_baseaphysrec; - int errorcode; - - - /* check parameter */ - if (fphysrec >= win_file->fphysrecs) - return IMGTOOLERR_UNEXPECTED; - - /* look for correct sibling */ - if (fphysrec < get_win_fdr_cursibFDR_basefphysrec(& win_file->curfdr)) - { - while (fphysrec < get_win_fdr_cursibFDR_basefphysrec(& win_file->curfdr)) - { - if (get_UINT16BE(win_file->curfdr.prevsibFDR_AU) == 0) - return IMGTOOLERR_CORRUPTIMAGE; - errorcode = win_goto_prev_sibFDR(win_file); - if (errorcode) - return errorcode; - } - } - else /*if (fphysrec >= get_win_fdr_cursibFDR_basefphysrec(& dsk_file->curfdr))*/ - { - while (fphysrec >= (get_win_fdr_cursibFDR_basefphysrec(& win_file->curfdr) - + get_UINT16BE(win_file->curfdr.sibFDR_AUlen) * win_file->l2_img->AUformat.physrecsperAU)) - { - if (get_UINT16BE(win_file->curfdr.nextsibFDR_AU) == 0) - return IMGTOOLERR_CORRUPTIMAGE; - errorcode = win_goto_next_sibFDR(win_file); - if (errorcode) - return errorcode; - } - } - - - /* search for the cluster in the data chain pointers array */ - cluster_firstfphysrec = get_win_fdr_cursibFDR_basefphysrec(& win_file->curfdr); - for (cluster_index = 0; cluster_index<54; cluster_index++) - { - cluster_lastfphysrec = cluster_firstfphysrec - + (get_UINT16BE(win_file->curfdr.clusters[cluster_index][1]) - - get_UINT16BE(win_file->curfdr.clusters[cluster_index][0]) - + 1) - * win_file->l2_img->AUformat.physrecsperAU; - if (fphysrec < cluster_lastfphysrec) - break; - - cluster_firstfphysrec = cluster_lastfphysrec; - } - - if (cluster_index == 54) - return IMGTOOLERR_CORRUPTIMAGE; - - - /* read base aphysrec address for this cluster */ - cluster_baseaphysrec = get_UINT16BE(win_file->curfdr.clusters[cluster_index][0]) * win_file->l2_img->AUformat.physrecsperAU; - /* return absolute physrec address */ - *aphysrec = cluster_baseaphysrec + (fphysrec - cluster_firstfphysrec); - return 0; -} - -/* - read a 256-byte physical record from a file -*/ -static int read_file_physrec(struct ti99_lvl2_fileref *l2_file, unsigned fphysrec, void *dest) -{ - int errorcode; - unsigned aphysrec; - - switch (l2_file->type) - { - case L2F_DSK: - /* compute absolute physrec address */ - errorcode = dsk_fphysrec_to_aphysrec(&l2_file->dsk, fphysrec, &aphysrec); - if (errorcode) - return errorcode; - /* read physrec */ - if (read_absolute_physrec(& l2_file->dsk.l2_img->l1_img, aphysrec, dest)) - return IMGTOOLERR_READERROR; - break; - - case L2F_WIN: - /* compute absolute physrec address */ - errorcode = win_fphysrec_to_aphysrec(&l2_file->win, fphysrec, &aphysrec); - if (errorcode) - return errorcode; - /* read physrec */ - if (read_absolute_physrec(& l2_file->win.l2_img->l1_img, aphysrec, dest)) - return IMGTOOLERR_READERROR; - break; - - case L2F_TIFILES: - /* seek to physrec */ - if (l2_file->tifiles.file_handle->seek(128+256*fphysrec, SEEK_SET)) - return IMGTOOLERR_READERROR; - /* read it */ - if (l2_file->tifiles.file_handle->read(dest, 256) != 256) - return IMGTOOLERR_READERROR; - break; - } - - return 0; -} - -/* - read a 256-byte physical record from a file -*/ -static int write_file_physrec(struct ti99_lvl2_fileref *l2_file, unsigned fphysrec, const void *src) -{ - int errorcode; - unsigned aphysrec; - - switch (l2_file->type) - { - case L2F_DSK: - /* compute absolute physrec address */ - errorcode = dsk_fphysrec_to_aphysrec(&l2_file->dsk, fphysrec, &aphysrec); - if (errorcode) - return errorcode; - /* write physrec */ - if (write_absolute_physrec(& l2_file->dsk.l2_img->l1_img, aphysrec, src)) - return IMGTOOLERR_WRITEERROR; - break; - - case L2F_WIN: - /* compute absolute physrec address */ - errorcode = win_fphysrec_to_aphysrec(&l2_file->win, fphysrec, &aphysrec); - if (errorcode) - return errorcode; - /* write physrec */ - if (write_absolute_physrec(& l2_file->win.l2_img->l1_img, aphysrec, src)) - return IMGTOOLERR_WRITEERROR; - break; - - case L2F_TIFILES: - /* seek to physrec */ - if (l2_file->tifiles.file_handle->seek(128+256*fphysrec, SEEK_SET)) - return IMGTOOLERR_WRITEERROR; - /* write it */ - if (l2_file->tifiles.file_handle->write(src, 256) != 256) - return IMGTOOLERR_WRITEERROR; - break; - } - - return 0; -} - -/* - 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) -{ - win_fdr fdr_buf; - unsigned fdr_aphysrec; - int errorcode = 0; - - 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)) - { - memcpy(((uint8_t *) &fdr_buf) + offset, data, size); - if (write_absolute_physrec(&l2_file->win.l2_img->l1_img, fdr_aphysrec, &fdr_buf)) - { - errorcode = IMGTOOLERR_WRITEERROR; - break; - } - } - - return errorcode; -} -#endif - -static uint8_t get_file_flags(struct ti99_lvl2_fileref *l2_file) -{ - int reply = 0; - - switch (l2_file->type) - { - case L2F_DSK: - reply = l2_file->dsk.fdr.flags; - break; - - case L2F_WIN: - reply = l2_file->win.curfdr.flags; - break; - - case L2F_TIFILES: - reply = l2_file->tifiles.hdr.flags; - break; - } - - return reply; -} - -static void set_file_flags(struct ti99_lvl2_fileref *l2_file, uint8_t data) -{ - switch (l2_file->type) - { - case L2F_DSK: - l2_file->dsk.fdr.flags = data; - break; - - case L2F_WIN: - l2_file->win.curfdr.flags = data; - break; - - case L2F_TIFILES: - l2_file->tifiles.hdr.flags = data; - break; - } -} - -static uint8_t get_file_recsperphysrec(struct ti99_lvl2_fileref *l2_file) -{ - int reply = 0; - - switch (l2_file->type) - { - case L2F_DSK: - reply = l2_file->dsk.fdr.recsperphysrec; - break; - - case L2F_WIN: - reply = l2_file->win.curfdr.recsperphysrec; - break; - - case L2F_TIFILES: - reply = l2_file->tifiles.hdr.recsperphysrec; - break; - } - - return reply; -} - -static void set_file_recsperphysrec(struct ti99_lvl2_fileref *l2_file, uint8_t data) -{ - switch (l2_file->type) - { - case L2F_DSK: - l2_file->dsk.fdr.recsperphysrec = data; - break; - - case L2F_WIN: - l2_file->win.curfdr.recsperphysrec = data; - break; - - case L2F_TIFILES: - l2_file->tifiles.hdr.recsperphysrec = data; - break; - } -} - -static unsigned get_file_fphysrecs(struct ti99_lvl2_fileref *l2_file) -{ - int reply = 0; - - switch (l2_file->type) - { - case L2F_DSK: - reply = get_UINT16BE(l2_file->dsk.fdr.fphysrecs); - break; - - case L2F_WIN: - reply = l2_file->win.fphysrecs; - break; - - case L2F_TIFILES: - reply = get_UINT16BE(l2_file->tifiles.hdr.fphysrecs); - break; - } - - return reply; -} - -static int set_file_fphysrecs(struct ti99_lvl2_fileref *l2_file, unsigned data) -{ - switch (l2_file->type) - { - case L2F_DSK: - if (data >= 65536) - return IMGTOOLERR_UNIMPLEMENTED; - set_UINT16BE(&l2_file->dsk.fdr.fphysrecs, data); - break; - - case L2F_WIN: - l2_file->win.fphysrecs = data; - break; - - case L2F_TIFILES: - if (data >= 65536) - return IMGTOOLERR_UNIMPLEMENTED; - set_UINT16BE(&l2_file->tifiles.hdr.fphysrecs, data); - break; - } - - return 0; -} - -static uint8_t get_file_eof(struct ti99_lvl2_fileref *l2_file) -{ - int reply = 0; - - switch (l2_file->type) - { - case L2F_DSK: - reply = l2_file->dsk.fdr.eof; - break; - - case L2F_WIN: - reply = l2_file->win.curfdr.eof; - break; - - case L2F_TIFILES: - reply = l2_file->tifiles.hdr.eof; - break; - } - - return reply; -} - -static void set_file_eof(struct ti99_lvl2_fileref *l2_file, uint8_t data) -{ - switch (l2_file->type) - { - case L2F_DSK: - l2_file->dsk.fdr.eof = data; - break; - - case L2F_WIN: - l2_file->win.curfdr.eof = data; - break; - - case L2F_TIFILES: - l2_file->tifiles.hdr.eof = data; - break; - } -} - -static uint16_t get_file_reclen(struct ti99_lvl2_fileref *l2_file) -{ - int reply = 0; - - switch (l2_file->type) - { - case L2F_DSK: - reply = l2_file->dsk.fdr.reclen; - if ((reply == 0) && (! (l2_file->dsk.fdr.flags & (fdr99_f_program /*| fdr99_f_var*/)))) - reply = get_UINT16BE(l2_file->dsk.fdr.xreclen); - break; - - case L2F_WIN: - reply = l2_file->win.curfdr.reclen; - if ((reply == 0) && (! (l2_file->win.curfdr.flags & (fdr99_f_program /*| fdr99_f_var*/)))) - reply = get_UINT16BE(l2_file->win.curfdr.xreclen); - break; - - case L2F_TIFILES: - reply = l2_file->tifiles.hdr.reclen; - break; - } - - return reply; -} - -static int set_file_reclen(struct ti99_lvl2_fileref *l2_file, uint16_t data) -{ - switch (l2_file->type) - { - case L2F_DSK: - if (data < 256) - { - l2_file->dsk.fdr.reclen = data; - set_UINT16BE(&l2_file->dsk.fdr.xreclen, 0); - } - else - { - l2_file->dsk.fdr.reclen = 0; - set_UINT16BE(&l2_file->dsk.fdr.xreclen, data); - } - break; - - case L2F_WIN: - if (data < 256) - { - l2_file->win.curfdr.reclen = data; - set_UINT16BE(&l2_file->win.curfdr.xreclen, 0); - } - else - { - l2_file->win.curfdr.reclen = 0; - set_UINT16BE(&l2_file->win.curfdr.xreclen, data); - } - break; - - case L2F_TIFILES: - if (data >= 256) - return IMGTOOLERR_UNIMPLEMENTED; - l2_file->tifiles.hdr.reclen = data; - break; - } - - return 0; -} - -static unsigned get_file_fixrecs(struct ti99_lvl2_fileref *l2_file) -{ - int reply = 0; - - switch (l2_file->type) - { - case L2F_DSK: - reply = get_UINT16LE(l2_file->dsk.fdr.fixrecs); - break; - - case L2F_WIN: - reply = get_win_fdr_fixrecs(&l2_file->win.curfdr); - break; - - case L2F_TIFILES: - reply = get_UINT16BE(l2_file->tifiles.hdr.fixrecs); - break; - } - - return reply; -} - -static int set_file_fixrecs(struct ti99_lvl2_fileref *l2_file, unsigned data) -{ - switch (l2_file->type) - { - case L2F_DSK: - if (data >= 65536) - return IMGTOOLERR_UNIMPLEMENTED; - set_UINT16LE(&l2_file->dsk.fdr.fixrecs, data); - break; - - case L2F_WIN: - set_win_fdr_fixrecs(&l2_file->win.curfdr, data); - break; - - case L2F_TIFILES: - if (data >= 65536) - return IMGTOOLERR_UNIMPLEMENTED; - set_UINT16BE(&l2_file->tifiles.hdr.fixrecs, data); - break; - } - - return 0; -} - -static void get_file_creation_date(struct ti99_lvl2_fileref *l2_file, ti99_date_time *reply) -{ - switch (l2_file->type) - { - case L2F_DSK: - *reply = l2_file->dsk.fdr.creation; - break; - - case L2F_WIN: - *reply = l2_file->win.curfdr.creation; - break; - - case L2F_TIFILES: - memset(reply, 0, sizeof(*reply)); - break; - } -} - -static void set_file_creation_date(struct ti99_lvl2_fileref *l2_file, ti99_date_time data) -{ - switch (l2_file->type) - { - case L2F_DSK: - l2_file->dsk.fdr.creation = data; - break; - - case L2F_WIN: - l2_file->win.curfdr.creation = data; - break; - - case L2F_TIFILES: - break; - } -} - -static void get_file_update_date(struct ti99_lvl2_fileref *l2_file, ti99_date_time *reply) -{ - switch (l2_file->type) - { - case L2F_DSK: - *reply = l2_file->dsk.fdr.update; - break; - - case L2F_WIN: - *reply = l2_file->win.curfdr.update; - break; - - case L2F_TIFILES: - memset(reply, 0, sizeof(*reply)); - break; - } -} - -static void set_file_update_date(struct ti99_lvl2_fileref *l2_file, ti99_date_time data) -{ - switch (l2_file->type) - { - case L2F_DSK: - l2_file->dsk.fdr.update = data; - break; - - case L2F_WIN: - l2_file->win.curfdr.update = data; - break; - - case L2F_TIFILES: - break; - } -} - -#ifdef UNUSED_FUNCTION -static void current_date_time(ti99_date_time *reply) -{ - /* All these functions should be ANSI */ - time_t cur_time = time(NULL); - struct tm expanded_time = *localtime(& cur_time); - - reply->time_MSB = (expanded_time.tm_hour << 3) | (expanded_time.tm_min >> 3); - reply->time_LSB = (expanded_time.tm_min << 5) | (expanded_time.tm_sec >> 1); - 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 - -#pragma mark LEVEL 3 DISK ROUTINES -#endif - -/* - Level 3 implements files as a succession of logical records. - - There are three types of files: - * program files that are not implemented at level 3 (no logical record) - * files with fixed-size records (random-access files) - * files with variable-size records (sequential-access) -*/ - -struct ti99_lvl3_fileref -{ - ti99_lvl2_fileref l2_file; - - int cur_log_rec; - int cur_phys_rec; - 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) -{ - l3_file->cur_log_rec = 0; - l3_file->cur_phys_rec = 0; - l3_file->cur_pos_in_phys_rec = 0; - - /*if ()*/ - - return 0; -} - -/* - Test a file for EOF -*/ -static int is_eof(ti99_lvl3_fileref *l3_file) -{ - int flags = get_file_flags(&l3_file->l2_file); - int fphysrecs = get_file_fphysrecs(&l3_file->l2_file); - int fdr_eof = get_file_eof(&l3_file->l2_file); - - if (flags & fdr99_f_var) - { - return (l3_file->cur_phys_rec >= fphysrecs); - } - else - { - return ((l3_file->cur_phys_rec >= fphysrecs) - || ((l3_file->cur_phys_rec == (fphysrecs-1)) - && (l3_file->cur_pos_in_phys_rec >= (fdr_eof ? fdr_eof : 256)))); - } -} - -/* - Read next record from a file -*/ -static int read_next_record(ti99_lvl3_fileref *l3_file, void *dest, int *out_reclen) -{ - int errorcode; - uint8_t physrec_buf[256]; - int reclen; - int flags = get_file_flags(&l3_file->l2_file); - int fphysrecs = get_file_fphysrecs(&l3_file->l2_file); - int fdr_eof = get_file_eof(&l3_file->l2_file); - - if (flags & fdr99_f_program) - { - /* program files have no level-3 record */ - return IMGTOOLERR_UNEXPECTED; - } - else if (flags & fdr99_f_var) - { - /* variable-length records */ - if (is_eof(l3_file)) - return IMGTOOLERR_UNEXPECTED; - errorcode = read_file_physrec(&l3_file->l2_file, l3_file->cur_phys_rec, physrec_buf); - if (errorcode) - return errorcode; - /* read reclen */ - reclen = physrec_buf[l3_file->cur_pos_in_phys_rec]; - /* check integrity */ - if ((reclen == 0xff) || (reclen > get_file_reclen(&l3_file->l2_file)) - || ((l3_file->cur_pos_in_phys_rec + 1 + reclen) > 256)) - return IMGTOOLERR_CORRUPTIMAGE; - /* copy to buffer */ - memcpy(dest, physrec_buf + l3_file->cur_pos_in_phys_rec + 1, reclen); - l3_file->cur_pos_in_phys_rec += reclen + 1; - /* skip to next physrec if needed */ - if ((l3_file->cur_pos_in_phys_rec == 256) - || (physrec_buf[l3_file->cur_pos_in_phys_rec] == 0xff)) - { - l3_file->cur_pos_in_phys_rec = 0; - l3_file->cur_phys_rec++; - } - (* out_reclen) = reclen; - } - else - { - /* fixed len records */ - reclen = get_file_reclen(&l3_file->l2_file); - if (is_eof(l3_file)) - return IMGTOOLERR_UNEXPECTED; - if ((l3_file->cur_pos_in_phys_rec + reclen) > 256) - { - l3_file->cur_pos_in_phys_rec = 0; - l3_file->cur_phys_rec++; - } - if ((l3_file->cur_phys_rec >= fphysrecs) - || ((l3_file->cur_phys_rec == (fphysrecs-1)) - && ((l3_file->cur_pos_in_phys_rec + reclen) >= (fdr_eof ? fdr_eof : 256)))) - return IMGTOOLERR_CORRUPTIMAGE; - errorcode = read_file_physrec(&l3_file->l2_file, l3_file->cur_phys_rec, physrec_buf); - if (errorcode) - return errorcode; - memcpy(dest, physrec_buf + l3_file->cur_pos_in_phys_rec, reclen); - l3_file->cur_pos_in_phys_rec += reclen; - if (l3_file->cur_pos_in_phys_rec == 256) - { - l3_file->cur_pos_in_phys_rec = 0; - l3_file->cur_phys_rec++; - } - (* out_reclen) = reclen; - } - - return 0; -} -#endif - -#if 0 -#pragma mark - -#pragma mark IMGTOOL MODULE IMPLEMENTATION -#endif - -/* - ti99 catalog iterator, used when imgtool reads the catalog -*/ -struct dsk_iterator -{ - struct ti99_lvl2_imgref *image; - int level; - int listing_subdirs; /* true if we are listing subdirectories at current level */ - int index[2]; /* current index in the disk catalog */ - ti99_catalog *cur_catalog; /* current catalog */ -}; - -struct win_iterator -{ - struct ti99_lvl2_imgref *image; - int level; - int listing_subdirs; /* true if we are listing subdirectories at current level */ - int index[MAX_DIR_LEVEL]; /* current index in the disk catalog */ - ti99_catalog catalog[MAX_DIR_LEVEL]; /* current catalog */ -}; - - -static imgtoolerr_t dsk_image_init_mess(imgtool::image &image, imgtool::stream::ptr &&stream); -static imgtoolerr_t dsk_image_init_v9t9(imgtool::image &image, imgtool::stream::ptr &&stream); -static imgtoolerr_t dsk_image_init_pc99_fm(imgtool::image &image, imgtool::stream::ptr &&stream); -static imgtoolerr_t dsk_image_init_pc99_mfm(imgtool::image &image, imgtool::stream::ptr &&stream); -static imgtoolerr_t win_image_init(imgtool::image &image, imgtool::stream::ptr &&stream); -static void ti99_image_exit(imgtool::image &img); -static void ti99_image_info(imgtool::image &img, std::ostream &stream); -static imgtoolerr_t dsk_image_beginenum(imgtool::directory &enumeration, const char *path); -static imgtoolerr_t dsk_image_nextenum(imgtool::directory &enumeration, imgtool_dirent &ent); -static imgtoolerr_t win_image_beginenum(imgtool::directory &enumeration, const char *path); -static imgtoolerr_t win_image_nextenum(imgtool::directory &enumeration, imgtool_dirent &ent); -static imgtoolerr_t ti99_image_freespace(imgtool::partition &partition, uint64_t *size); -static imgtoolerr_t ti99_image_readfile(imgtool::partition &partition, const char *fpath, const char *fork, imgtool::stream &destf); -static imgtoolerr_t ti99_image_writefile(imgtool::partition &partition, const char *fpath, const char *fork, imgtool::stream &sourcef, util::option_resolution *writeoptions); -static imgtoolerr_t dsk_image_deletefile(imgtool::partition &partition, const char *fpath); -static imgtoolerr_t win_image_deletefile(imgtool::partition &partition, const char *fpath); -static imgtoolerr_t dsk_image_create_mess(imgtool::image &image, imgtool::stream::ptr &&stream, util::option_resolution *createoptions); -static imgtoolerr_t dsk_image_create_v9t9(imgtool::image &image, imgtool::stream::ptr &&stream, util::option_resolution *createoptions); - -enum -{ - dsk_createopts_volname = 'A', - dsk_createopts_sides = 'B', - dsk_createopts_tracks = 'C', - dsk_createopts_sectors = 'D', - dsk_createopts_protection = 'E', - dsk_createopts_density = 'F' -}; - -OPTION_GUIDE_START( dsk_create_optionguide ) - OPTION_STRING(dsk_createopts_volname, "label", "Volume name" ) - OPTION_INT(dsk_createopts_sides, "sides", "Sides" ) - OPTION_INT(dsk_createopts_tracks, "tracks", "Tracks" ) - OPTION_INT(dsk_createopts_sectors, "sectors", "Sectors (1->9 for SD, 1->18 for DD, 1->36 for HD)" ) - OPTION_INT(dsk_createopts_protection, "protection", "Protection (0 for normal, 1 for protected)" ) - OPTION_ENUM_START(dsk_createopts_density, "density", "Density" ) - OPTION_ENUM( 0, "Auto", "Auto" ) - OPTION_ENUM( 1, "SD", "Single Density" ) - OPTION_ENUM( 2, "DD", "Double Density" ) - OPTION_ENUM( 3, "HD", "High Density" ) - OPTION_ENUM_END -OPTION_GUIDE_END - -#define dsk_create_optionspecs "B1-[2];C1-[40]-80;D1-[18]-36;E[0]-1;F[0]-3" - -static void ti99_getinfo(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info) -{ - switch(state) - { - case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES: info->i = sizeof(ti99_lvl2_imgref); break; - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(dsk_iterator); break; - - case IMGTOOLINFO_STR_EOLN: strcpy(info->s = imgtool_temp_str(), "\r"); break; - case IMGTOOLINFO_PTR_CLOSE: info->close = ti99_image_exit; break; - case IMGTOOLINFO_PTR_INFO: info->info = ti99_image_info; break; - case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = ti99_image_freespace; break; - case IMGTOOLINFO_PTR_READ_FILE: info->read_file = ti99_image_readfile; break; - case IMGTOOLINFO_PTR_WRITE_FILE: info->write_file = ti99_image_writefile; break; - } -} - -static void ti99_dsk_getinfo(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info) -{ - switch(state) - { - case IMGTOOLINFO_STR_FILE_EXTENSIONS: strcpy(info->s = imgtool_temp_str(), "dsk"); break; - case IMGTOOLINFO_PTR_BEGIN_ENUM: info->begin_enum = dsk_image_beginenum; break; - case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = dsk_image_nextenum; break; - case IMGTOOLINFO_PTR_DELETE_FILE: info->delete_file = dsk_image_deletefile; break; - default: ti99_getinfo(imgclass, state, info); - } -} - -void ti99_old_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info) -{ - switch(state) - { - case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "ti99_old"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "TI99 Diskette (old MESS format)"); break; - case IMGTOOLINFO_PTR_OPEN: info->open = dsk_image_init_mess; break; - case IMGTOOLINFO_PTR_CREATE: info->create = dsk_image_create_mess; break; - case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE: info->createimage_optguide = &dsk_create_optionguide; break; - case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC: strcpy(info->s = imgtool_temp_str(), dsk_create_optionspecs); break; - default: ti99_dsk_getinfo(imgclass, state, info); break; - } -} - -void ti99_v9t9_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info) -{ - switch(state) - { - case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "v9t9"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "TI99 Diskette (V9T9 format)"); break; - case IMGTOOLINFO_PTR_OPEN: info->open = dsk_image_init_v9t9; break; - case IMGTOOLINFO_PTR_CREATE: info->create = dsk_image_create_v9t9; break; - case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE: info->createimage_optguide = &dsk_create_optionguide; break; - case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC: strcpy(info->s = imgtool_temp_str(), dsk_create_optionspecs); break; - default: ti99_dsk_getinfo(imgclass, state, info); break; - } -} - -void ti99_pc99fm_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info) -{ - switch(state) - { - case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "pc99fm"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "TI99 Diskette (PC99 FM format)"); break; - case IMGTOOLINFO_PTR_OPEN: info->open = dsk_image_init_pc99_fm; break; - case IMGTOOLINFO_PTR_CREATE: /* info->create = dsk_image_create_pc99fm; */ break; - default: ti99_dsk_getinfo(imgclass, state, info); break; - } -} - -void ti99_pc99mfm_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info) -{ - switch(state) - { - case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "pc99mfm"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "TI99 Diskette (PC99 MFM format)"); break; - case IMGTOOLINFO_PTR_OPEN: info->open = dsk_image_init_pc99_mfm; break; - case IMGTOOLINFO_PTR_CREATE: /* info->create = dsk_image_create_pc99mfm; */ break; - default: ti99_dsk_getinfo(imgclass, state, info); break; - } -} - -void ti99_ti99hd_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info) -{ - switch(state) - { - case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "ti99hd"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "TI99 Harddisk"); break; - case IMGTOOLINFO_PTR_OPEN: info->open = win_image_init; break; - case IMGTOOLINFO_PTR_CREATE: /* info->create = hd_image_create; */ break; - - case IMGTOOLINFO_STR_FILE_EXTENSIONS: strcpy(info->s = imgtool_temp_str(), "hd"); break; - case IMGTOOLINFO_PTR_BEGIN_ENUM: info->begin_enum = win_image_beginenum; break; - case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = win_image_nextenum; break; - case IMGTOOLINFO_PTR_DELETE_FILE: info->delete_file = win_image_deletefile; break; - default: ti99_getinfo(imgclass, state, info); - } -} - - - -/* - Open a file as a ti99_image (common code). -*/ -static imgtoolerr_t dsk_image_init(imgtool::image &img, imgtool::stream::ptr &&stream, ti99_img_format img_format) -{ - struct ti99_lvl2_imgref *image = get_lvl2_imgref(img); - dsk_vib vib; - imgtoolerr_t reply; - int totphysrecs; - unsigned fdir_aphysrec; - int i; - - /* open disk image at level 1 */ - reply = open_image_lvl1(std::move(stream), img_format, &image->l1_img, &vib); - if (reply) - return reply; - - /* open disk image at level 2 */ - image->type = L2I_DSK; - - /* @BN@ */ - /* Copy in the allocation bit map! */ - memcpy(image->abm, vib.abm, 200); - /* first compute AU size and number of AUs */ - totphysrecs = get_UINT16BE(vib.totphysrecs); - - image->AUformat.physrecsperAU = (totphysrecs + 1599) / 1600; - /* round to next larger power of 2 */ - for (i = 1; i < image->AUformat.physrecsperAU; i <<= 1) - ; - image->AUformat.physrecsperAU = i; - image->AUformat.totAUs = totphysrecs / image->AUformat.physrecsperAU; - - /* extract number of physrecs */ - image->dsk.totphysrecs = get_UINT16BE(vib.totphysrecs); - - /* read and check main volume catalog */ - reply = (imgtoolerr_t)dsk_read_catalog(image, 1, &image->dsk.catalogs[0]); - if (reply) - return reply; - - image->dsk.fdir_aphysrec[0] = 1; - - /* read and check subdirectory catalogs */ - /* Note that the reserved areas used for HFDC subdirs may be used for other - purposes by other FDRs, so, if we get any error, we will assume there is no - subdir after all... */ - image->dsk.catalogs[0].num_subdirs = 0; - for (i=0; i<3; i++) - { - fdir_aphysrec = get_UINT16BE(vib.subdir[i].fdir_aphysrec); - if ((! memcmp(vib.subdir[i].name, "\0\0\0\0\0\0\0\0\0\0", 10)) - || (! memcmp(vib.subdir[i].name, " ", 10))) - { - /* name is empty: fine with us unless there is a fdir pointer */ - if (fdir_aphysrec != 0) - { - image->dsk.catalogs[0].num_subdirs = 0; - break; - } - } - else if (check_fname(vib.subdir[i].name)) - { - /* name is invalid: this is not an HFDC format floppy */ - image->dsk.catalogs[0].num_subdirs = 0; - break; - } - else - { - /* there is a non-empty name */ - if ((fdir_aphysrec == 0) || (fdir_aphysrec >= totphysrecs)) - { - /* error: fdir pointer is invalid or NULL */ - image->dsk.catalogs[0].num_subdirs = 0; - break; - } - /* fill in descriptor fields */ - image->dsk.fdir_aphysrec[image->dsk.catalogs[0].num_subdirs+1] = fdir_aphysrec; - /*image->dsk.catalogs[0].subdirs[image->dsk.catalogs[0].num_subdirs].dir_ptr = fdir_aphysrec;*/ - memcpy(image->dsk.catalogs[0].subdirs[image->dsk.catalogs[0].num_subdirs].name, vib.subdir[i].name, 10); - reply = (imgtoolerr_t) dsk_read_catalog(image, fdir_aphysrec, &image->dsk.catalogs[image->dsk.catalogs[0].num_subdirs+1]); - if (reply) - { - /* error: invalid fdir */ - image->dsk.catalogs[0].num_subdirs = 0; - break; - } - /* found valid subdirectory: increment subdir count */ - image->dsk.catalogs[0].num_subdirs++; - } - } - - /* extract volume name */ - memcpy(image->vol_name, vib.name, 10); - - /* initialize default data_offset */ - image->data_offset = 32+2; - - return (imgtoolerr_t)0; -} - -/* - Open a file as a ti99_image (MESS format). -*/ -static imgtoolerr_t dsk_image_init_mess(imgtool::image &image, imgtool::stream::ptr &&stream) -{ - return dsk_image_init(image, std::move(stream), if_mess); -} - -/* - Open a file as a ti99_image (V9T9 format). -*/ -static imgtoolerr_t dsk_image_init_v9t9(imgtool::image &image, imgtool::stream::ptr &&stream) -{ - return dsk_image_init(image, std::move(stream), if_v9t9); -} - -/* - Open a file as a ti99_image (PC99 FM format). -*/ -static imgtoolerr_t dsk_image_init_pc99_fm(imgtool::image &image, imgtool::stream::ptr &&stream) -{ - return dsk_image_init(image, std::move(stream), if_pc99_fm); -} - -/* - Open a file as a ti99_image (PC99 MFM format). -*/ -static imgtoolerr_t dsk_image_init_pc99_mfm(imgtool::image &image, imgtool::stream::ptr &&stream) -{ - return dsk_image_init(image, std::move(stream), if_pc99_mfm); -} - -/* - Open a file as a ti99_image (harddisk format). -*/ -static imgtoolerr_t win_image_init(imgtool::image &img, imgtool::stream::ptr &&stream) -{ - struct ti99_lvl2_imgref *image = get_lvl2_imgref(img); - win_vib_ddr vib; - int reply; - int i; - - /* open disk image at level 1 */ - reply = open_image_lvl1(std::move(stream), if_harddisk, & image->l1_img, NULL); - if (reply) - return (imgtoolerr_t)reply; - - /* open disk image at level 2 */ - image->type = L2I_WIN; - - /* read VIB */ - reply = read_absolute_physrec(&image->l1_img, 0, &vib); - if (reply) - return (imgtoolerr_t)reply; - - /* guess VIB version */ - image->win.vib_version = memcmp(vib.u.vib_v1.id, "WIN", 3) ? win_vib_v2 : win_vib_v1; - - /* extract AU size and number of AUs */ - image->AUformat.physrecsperAU = ((get_UINT16BE(vib.params) >> 12) & 0xf) + 1; - image->AUformat.totAUs = get_UINT16BE(vib.totAUs); - - /* extract volume name */ - memcpy(image->vol_name, vib.name, 10); - - /* extract data_offset */ - switch (image->win.vib_version) - { - case win_vib_v1: - image->data_offset = 64; - break; - - case win_vib_v2: - image->data_offset = vib.u.vib_v2.res_AUs * 64; - break; - } - - /* read allocation bitmap (aphysrecs 1 through n, n<=33) */ - for (i=0; i < (image->AUformat.totAUs+2047)/2048; i++) - { - reply = read_absolute_physrec(&image->l1_img, i+1, image->abm+i*256); - if (reply) - return (imgtoolerr_t)reply; - } - - return (imgtoolerr_t)0; -} - -/* - close a ti99_image -*/ -static void ti99_image_exit(imgtool::image &img) -{ - struct ti99_lvl2_imgref *image = get_lvl2_imgref(img); - - close_image_lvl1(&image->l1_img); -} - -/* - get basic information on a ti99_image - - Currently returns the volume name -*/ -static void ti99_image_info(imgtool::image &img, std::ostream &stream) -{ - struct ti99_lvl2_imgref *image = get_lvl2_imgref(img); - char vol_name[11]; - - fname_to_str(vol_name, image->vol_name, 11); - - stream << vol_name; -} - -/* - Open the disk catalog for enumeration -*/ -static imgtoolerr_t dsk_image_beginenum(imgtool::directory &enumeration, const char *path) -{ - struct ti99_lvl2_imgref *image = get_lvl2_imgref(enumeration.image()); - dsk_iterator *iter = (dsk_iterator *) enumeration.extra_bytes(); - - iter->image = image; - iter->level = 0; - iter->listing_subdirs = 1; - iter->index[0] = 0; - iter->cur_catalog = &iter->image->dsk.catalogs[0]; - - return (imgtoolerr_t)0; -} - -/* - Enumerate disk catalog next entry -*/ -static imgtoolerr_t dsk_image_nextenum(imgtool::directory &enumeration, imgtool_dirent &ent) -{ - dsk_iterator *iter = (dsk_iterator*) enumeration.extra_bytes(); - dsk_fdr fdr; - int reply; - unsigned fdr_aphysrec; - - - ent.corrupt = 0; - ent.eof = 0; - - /* iterate through catalogs to next file or dir entry */ - while ((iter->level >= 0) - && (iter->index[iter->level] >= (iter->listing_subdirs - ? iter->cur_catalog->num_subdirs - : iter->cur_catalog->num_files))) - { - if (iter->listing_subdirs) - { - iter->listing_subdirs = 0; - iter->index[iter->level] = 0; - } - else - { - iter->listing_subdirs = 1; - if (! iter->level) - iter->level = -1; - else - { - iter->level = 0; - iter->index[0]++; - iter->cur_catalog = &iter->image->dsk.catalogs[0]; - } - } - } - - if (iter->level < 0) - { - ent.eof = 1; - } - else - { - if (iter->listing_subdirs) - { - 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, std::size(ent.attr), "DIR"); - - /* len in physrecs */ - /* @BN@ return length in bytes */ - /* ent.filesize = 1; */ - ent.filesize = 256; - - /* recurse subdirectory */ - iter->listing_subdirs = 0; /* no need to list subdirs as only the - root dir has subdirs in DSK format */ - iter->level = 1; - iter->cur_catalog = &iter->image->dsk.catalogs[iter->index[0]+1]; - iter->index[iter->level] = 0; - } - else - { - fdr_aphysrec = iter->cur_catalog->files[iter->index[iter->level]].fdr_ptr; - reply = read_absolute_physrec(& iter->image->l1_img, fdr_aphysrec, & fdr); - if (reply) - return IMGTOOLERR_READERROR; -#if 0 - fname_to_str(ent.filename, fdr.name, std::size(ent.filename)); -#else - { - char buf[11]; - - ent.filename[0] = '\0'; - if (iter->level) - { - 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, std::size(ent.filename) - 1); - } -#endif - /* parse flags */ - if (fdr.flags & fdr99_f_program) - snprintf(ent.attr, std::size(ent.attr), "PGM%s", - (fdr.flags & fdr99_f_wp) ? " R/O" : ""); - else - 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, - (fdr.flags & fdr99_f_wp) ? " R/O" : ""); - /* len in physrecs */ - /* @BN@ return length in bytes */ - /* ent.filesize = get_UINT16BE(fdr.fphysrecs); */ - ent.filesize = (get_UINT16BE(fdr.fphysrecs)+1)*256; - - iter->index[iter->level]++; - } - } - - return (imgtoolerr_t)0; -} - -/* - Open the disk catalog for enumeration -*/ -static imgtoolerr_t win_image_beginenum(imgtool::directory &enumeration, const char *path) -{ - struct ti99_lvl2_imgref *image = get_lvl2_imgref(enumeration.image()); - win_iterator *iter = (win_iterator *) enumeration.extra_bytes(); - imgtoolerr_t errorcode; - - iter->image = image; - iter->level = 0; - iter->listing_subdirs = 1; - iter->index[0] = 0; - errorcode = (imgtoolerr_t)win_read_catalog(image, 0, &iter->catalog[0]); - if (errorcode) - return errorcode; - - return (imgtoolerr_t)0; -} - -/* - Enumerate disk catalog next entry -*/ -static imgtoolerr_t win_image_nextenum(imgtool::directory &enumeration, imgtool_dirent &ent) -{ - win_iterator *iter = (win_iterator *) enumeration.extra_bytes(); - unsigned fdr_aphysrec; - win_fdr fdr; - int reply; - int i; - - - ent.corrupt = 0; - ent.eof = 0; - - /* iterate through catalogs to next file or dir entry */ - while ((iter->level >= 0) - && (iter->index[iter->level] >= (iter->listing_subdirs - ? iter->catalog[iter->level].num_subdirs - : iter->catalog[iter->level].num_files))) - { - if (iter->listing_subdirs) - { - iter->listing_subdirs = 0; - iter->index[iter->level] = 0; - } - else - { - iter->listing_subdirs = 1; - iter->level--; - iter->index[iter->level]++; - } - } - - if (iter->level < 0) - { - ent.eof = 1; - } - else - { - if (iter->listing_subdirs) - { -#if 0 - fname_to_str(ent.filename, iter->catalog[iter->level].subdirs[iter->index[iter->level]].name, std::size(ent.filename)); -#else - { - char buf[11]; - - ent.filename[0] = '\0'; - for (i=0; ilevel; i++) - { - fname_to_str(buf, iter->catalog[i].subdirs[iter->index[i]].name, 11); - 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, std::size(ent.filename) - 1); - } -#endif - - /* set type of DIR */ - snprintf(ent.attr, std::size(ent.attr), "DIR"); - - /* len in physrecs */ - /* @BN@ return length in bytes */ - /* ent.filesize = 2; */ - ent.filesize = 512; - - /* recurse subdirectory */ - /*iter->listing_subdirs = 1;*/ - iter->level++; - iter->index[iter->level] = 0; - reply = win_read_catalog(iter->image, iter->catalog[iter->level-1].subdirs[iter->index[iter->level-1]].dir_ptr, &iter->catalog[iter->level]); - if (reply) - { - ent.corrupt = 1; - return (imgtoolerr_t)reply; - } - } - else - { - fdr_aphysrec = iter->catalog[iter->level].files[iter->index[iter->level]].fdr_ptr*iter->image->AUformat.physrecsperAU; - reply = read_absolute_physrec(& iter->image->l1_img, fdr_aphysrec, & fdr); - if (reply) - return IMGTOOLERR_READERROR; -#if 0 - fname_to_str(ent.filename, iter->catalog[iter->level].files[iter->index[iter->level]].name, std::size(ent.filename)); -#else - { - char buf[11]; - - ent.filename[0] = '\0'; - for (i=0; ilevel; i++) - { - fname_to_str(buf, iter->catalog[i].subdirs[iter->index[i]].name, 11); - 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, std::size(ent.filename) - 1); - } -#endif - /* parse flags */ - if (fdr.flags & fdr99_f_program) - snprintf(ent.attr, std::size(ent.attr), "PGM%s", - (fdr.flags & fdr99_f_wp) ? " R/O" : ""); - else - 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, - (fdr.flags & fdr99_f_wp) ? " R/O" : ""); - /* len in physrecs */ - /* @BN@ return length in bytes */ - /* ent.filesize = get_win_fdr_fphysrecs(&fdr); */ - ent.filesize = (get_win_fdr_fphysrecs(&fdr)+1)*256; - - iter->index[iter->level]++; - } - } - - return (imgtoolerr_t)0; -} - -/* - Compute free space on disk image (in AUs) -*/ -static imgtoolerr_t ti99_image_freespace(imgtool::partition &partition, uint64_t *size) -{ - imgtool::image &img(partition.image()); - struct ti99_lvl2_imgref *image = get_lvl2_imgref(img); - size_t freeAUs; - int i; - - freeAUs = 0; - for (i=0; iAUformat.totAUs; i++) - { - if (! (image->abm[i >> 3] & (1 << (i & 7)))) - freeAUs++; - } - - /* @BN@ return free space in bytes */ - /* *size = freeAUs; */ - *size = freeAUs*256; - - return IMGTOOLERR_SUCCESS; -} - -/* - Extract a file from a ti99_image. The file is saved in tifile format. -*/ -static imgtoolerr_t ti99_image_readfile(imgtool::partition &partition, const char *fpath, const char *fork, imgtool::stream &destf) -{ - imgtool::image &img(partition.image()); -#if 1 - - /* extract data as TIFILES */ - struct ti99_lvl2_imgref *image = get_lvl2_imgref(img); - ti99_lvl2_fileref src_file; - ti99_lvl2_fileref dst_file; - ti99_date_time date_time; - int fphysrecs; - int i; - uint8_t buf[256]; - imgtoolerr_t errorcode; - - - if (check_fpath(fpath)) - return IMGTOOLERR_BADFILENAME; - - /* open file on TI image */ - switch (image->type) - { - case L2I_DSK: - errorcode = (imgtoolerr_t)open_file_lvl2_dsk(image, fpath, &src_file); - break; - - case L2I_WIN: - errorcode = (imgtoolerr_t)open_file_lvl2_win(image, fpath, &src_file); - break; - - default: - errorcode = (imgtoolerr_t)-1; - break; - } - if (errorcode) - return errorcode; - - errorcode = (imgtoolerr_t)new_file_lvl2_tifiles(destf, &dst_file); - if (errorcode) - return errorcode; - - /* write TIFILE header */ - /* set up parameters */ - set_file_flags(&dst_file, get_file_flags(&src_file)); - set_file_recsperphysrec(&dst_file, get_file_recsperphysrec(&src_file)); - errorcode = (imgtoolerr_t)set_file_fphysrecs(&dst_file, get_file_fphysrecs(&src_file)); - if (errorcode) - return errorcode; - set_file_eof(&dst_file, get_file_eof(&src_file)); - errorcode = (imgtoolerr_t)set_file_reclen(&dst_file, get_file_reclen(&src_file)); - if (errorcode) - return errorcode; - errorcode = (imgtoolerr_t)set_file_fixrecs(&dst_file, get_file_fixrecs(&src_file)); - if (errorcode) - return errorcode; - - get_file_creation_date(&src_file, &date_time); -#if 0 - if ((date_time.time_MSB == 0) || (date_time.time_LSB == 0) - || (date_time.date_MSB == 0) || (date_time.date_LSB == 0)) - current_date_time(&date_time); -#endif - set_file_creation_date(&dst_file, date_time); - - get_file_update_date(&src_file, &date_time); -#if 0 - if ((date_time.time_MSB == 0) || (date_time.time_LSB == 0) - || (date_time.date_MSB == 0) || (date_time.date_LSB == 0)) - current_date_time(&date_time); -#endif - set_file_update_date(&dst_file, date_time); - - if (destf.write(& dst_file.tifiles.hdr, 128) != 128) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - - /* copy data to TIFILE */ - fphysrecs = get_file_fphysrecs(&src_file); - - for (i=0; itype) - { - case L2I_DSK: - errorcode = open_file_lvl2_dsk(image, fpath, &src_file.l2_file); - break; - - case L2I_WIN: - errorcode = open_file_lvl2_win(image, fpath, &src_file.l2_file); - break; - } - if (errorcode) - return errorcode; - - errorcode = open_file_lvl3(& src_file); - if (errorcode) - return errorcode; - - /* write text data */ - while (! is_eof(& src_file)) - { - errorcode = read_next_record(& src_file, buf, & reclen); - if (errorcode) - return errorcode; - if (destf.write(buf, reclen) != reclen) - return IMGTOOLERR_WRITEERROR; - if (destf.write(&lineend, 1) != 1) - return IMGTOOLERR_WRITEERROR; - } - - return 0; - -#endif -} - -/* - Add a file to a ti99_image. The file must be in tifile format. -*/ -static imgtoolerr_t ti99_image_writefile(imgtool::partition &partition, const char *fpath, const char *fork, imgtool::stream &sourcef, util::option_resolution *writeoptions) -{ - imgtool::image &img(partition.image()); - struct ti99_lvl2_imgref *image = get_lvl2_imgref(img); - const char *filename; - char ti_fname[10]; - ti99_lvl2_fileref src_file; - ti99_lvl2_fileref dst_file; - ti99_date_time date_time; - int i; - int fphysrecs; - uint8_t buf[256]; - imgtoolerr_t errorcode; - int parent_ref_valid, parent_ref = 0; - ti99_catalog *catalog, catalog_buf = {0, }; - - - (void) writeoptions; - - if (check_fpath(fpath)) - return IMGTOOLERR_BADFILENAME; - - switch (image->type) - { - case L2I_DSK: - errorcode = (imgtoolerr_t)dsk_find_catalog_entry(image, fpath, &parent_ref_valid, &parent_ref, NULL, NULL); - if (errorcode == 0) - /* file already exists: causes an error for now */ - return (imgtoolerr_t)IMGTOOLERR_UNEXPECTED; - else if ((! parent_ref_valid) || (errorcode != IMGTOOLERR_FILENOTFOUND)) - return (imgtoolerr_t)errorcode; - break; - - case L2I_WIN: - errorcode = (imgtoolerr_t)win_find_catalog_entry(image, fpath, &parent_ref_valid, &parent_ref, &catalog_buf, NULL, NULL); - if (errorcode == 0) - /* file already exists: causes an error for now */ - return (imgtoolerr_t)IMGTOOLERR_UNEXPECTED; - else if ((! parent_ref_valid) || (errorcode != IMGTOOLERR_FILENOTFOUND)) - return (imgtoolerr_t)errorcode; - break; - } - - errorcode =(imgtoolerr_t) open_file_lvl2_tifiles(sourcef, & src_file); - if (errorcode) - return (imgtoolerr_t)errorcode; - - /* create new file */ - filename = strrchr(fpath, '.'); - if (filename) - filename++; - else - filename = fpath; - str_to_fname(ti_fname, filename); - switch (image->type) - { - case L2I_DSK: - errorcode = (imgtoolerr_t)new_file_lvl2_dsk(image, parent_ref, ti_fname, &dst_file); - if (errorcode) - return (imgtoolerr_t)errorcode; - break; - - case L2I_WIN: - errorcode = (imgtoolerr_t)new_file_lvl2_win(image, &catalog_buf, ti_fname, &dst_file); - if (errorcode) - return (imgtoolerr_t)errorcode; - break; - } - - /* set up parameters */ - set_file_flags(&dst_file, get_file_flags(&src_file)); - set_file_recsperphysrec(&dst_file, get_file_recsperphysrec(&src_file)); - errorcode = (imgtoolerr_t)set_file_fphysrecs(&dst_file, /*get_file_fphysrecs(&src_file)*/0); - if (errorcode) - return (imgtoolerr_t)errorcode; - set_file_eof(&dst_file, get_file_eof(&src_file)); - errorcode = (imgtoolerr_t)set_file_reclen(&dst_file, get_file_reclen(&src_file)); - if (errorcode) - return (imgtoolerr_t)errorcode; - errorcode = (imgtoolerr_t)set_file_fixrecs(&dst_file, get_file_fixrecs(&src_file)); - if (errorcode) - return (imgtoolerr_t)errorcode; - - get_file_creation_date(&src_file, &date_time); -#if 0 - if ((date_time.time_MSB == 0) || (date_time.time_LSB == 0) - || (date_time.date_MSB == 0) || (date_time.date_LSB == 0)) - current_date_time(&date_time); -#endif - set_file_creation_date(&dst_file, date_time); - - get_file_update_date(&src_file, &date_time); -#if 0 - if ((date_time.time_MSB == 0) || (date_time.time_LSB == 0) - || (date_time.date_MSB == 0) || (date_time.date_LSB == 0)) - current_date_time(&date_time); -#endif - set_file_update_date(&dst_file, date_time); - - /* alloc data physrecs */ - fphysrecs = get_file_fphysrecs(&src_file); - switch (dst_file.type) - { - case L2F_DSK: - errorcode = (imgtoolerr_t)dsk_alloc_file_physrecs(&dst_file.dsk, fphysrecs); - if (errorcode) - return (imgtoolerr_t)errorcode; - break; - - case L2F_WIN: - errorcode = (imgtoolerr_t)win_alloc_file_physrecs(&dst_file.win, fphysrecs); - if (errorcode) - return (imgtoolerr_t)errorcode; - break; - - case L2F_TIFILES: - break; - } - - /* copy data */ - for (i=0; itype) - { - case L2I_DSK: - if (write_absolute_physrec(& image->l1_img, dst_file.dsk.fdr_aphysrec, &dst_file.dsk.fdr)) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - break; - - case L2I_WIN: - /* save fphysrecs field as well */ - if (dst_file.win.curfdr_aphysrec == dst_file.win.eldestfdr_aphysrec) - set_win_fdr_fphysrecs(&dst_file.win.curfdr, dst_file.win.fphysrecs); - if (write_absolute_physrec(& image->l1_img, dst_file.win.curfdr_aphysrec, &dst_file.win.curfdr)) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - if (dst_file.win.curfdr_aphysrec != dst_file.win.eldestfdr_aphysrec) - { - dst_file.win.curfdr_aphysrec = dst_file.win.eldestfdr_aphysrec; - if (read_absolute_physrec(& image->l1_img, dst_file.win.curfdr_aphysrec, &dst_file.win.curfdr)) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - set_win_fdr_fphysrecs(&dst_file.win.curfdr, dst_file.win.fphysrecs); - if (write_absolute_physrec(& image->l1_img, dst_file.win.curfdr_aphysrec, &dst_file.win.curfdr)) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - } - break; - } - - /* update catalog */ - switch (image->type) - { - case L2I_DSK: - catalog = &image->dsk.catalogs[parent_ref]; - for (i=0; i<128; i++) - { - buf[2*i] = catalog->files[i].fdr_ptr >> 8; - buf[2*i+1] = catalog->files[i].fdr_ptr & 0xff; - } - if (write_absolute_physrec(& image->l1_img, image->dsk.fdir_aphysrec[parent_ref], buf)) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - break; - - case L2I_WIN: - { - win_vib_ddr parent_ddr; - int fdir_AU; - - /* update VIB/DDR and get FDIR AU address */ - if (read_absolute_physrec(& image->l1_img, parent_ref * image->AUformat.physrecsperAU, &parent_ddr)) - return (imgtoolerr_t)IMGTOOLERR_READERROR; - parent_ddr.num_files = catalog_buf.num_files; - if (write_absolute_physrec(& image->l1_img, parent_ref * image->AUformat.physrecsperAU, &parent_ddr)) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - fdir_AU = get_UINT16BE(parent_ddr.fdir_AU); - - /* generate FDIR and save it */ - for (i=0; i<127; i++) - { - buf[2*i] = catalog_buf.files[i].fdr_ptr >> 8; - buf[2*i+1] = catalog_buf.files[i].fdr_ptr & 0xff; - } - buf[254] = parent_ref >> 8; - buf[255] = parent_ref & 0xff; - if (write_absolute_physrec(& image->l1_img, fdir_AU * image->AUformat.physrecsperAU, buf)) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - } - break; - } - - /* update bitmap */ - switch (image->type) - { - case L2I_DSK: - { - dsk_vib vib; - - if (read_absolute_physrec(& image->l1_img, 0, &vib)) - return (imgtoolerr_t)IMGTOOLERR_READERROR; - memcpy(vib.abm, image->abm, 200); - if (write_absolute_physrec(& image->l1_img, 0, &vib)) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - } - break; - - case L2I_WIN: - /* save allocation bitmap (aphysrecs 1 through n, n<=33) */ - for (i=0; i < (image->AUformat.totAUs+2047)/2048; i++) - if (write_absolute_physrec(&image->l1_img, i+1, image->abm+i*256)) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - break; - } - - return (imgtoolerr_t)0; -} - -/* - Delete a file from a ti99_image. -*/ -static imgtoolerr_t dsk_image_deletefile(imgtool::partition &partition, const char *fpath) -{ - imgtool::image &img(partition.image()); - struct ti99_lvl2_imgref *image = get_lvl2_imgref(img); - dsk_fdr fdr; - int i, cluster_index; - unsigned cur_AU, cluster_lastfphysrec; -// int fphysrecs; - int parent_ref, is_dir, catalog_index; - imgtoolerr_t errorcode; - uint8_t buf[256]; - ti99_catalog *catalog; - - - if (check_fpath(fpath)) - return IMGTOOLERR_BADFILENAME; - - errorcode = (imgtoolerr_t)dsk_find_catalog_entry(image, fpath, NULL, &parent_ref, &is_dir, &catalog_index); - if (errorcode) - return errorcode; - - if (is_dir) - { - catalog = &image->dsk.catalogs[catalog_index+1]; - - if ((catalog->num_files != 0) || (catalog->num_subdirs != 0)) - return IMGTOOLERR_UNIMPLEMENTED; - - catalog = &image->dsk.catalogs[0]; - - /* free fdir AU */ - cur_AU = image->dsk.fdir_aphysrec[catalog_index+1] / image->AUformat.physrecsperAU; - image->abm[cur_AU >> 3] &= ~ (1 << (cur_AU & 7)); - - /* delete catalog entry */ - for (i=catalog_index; i<2; i++) - { - catalog->subdirs[i] = catalog->subdirs[i+1]; - image->dsk.fdir_aphysrec[i+1] = image->dsk.fdir_aphysrec[i+2]; - } - memset(catalog->subdirs[2].name, 0, 10); - catalog->subdirs[2].dir_ptr = 0; - image->dsk.fdir_aphysrec[3] = 0; - catalog->num_subdirs--; - - /* update directory and bitmap in vib */ - { - dsk_vib vib; - - if (read_absolute_physrec(& image->l1_img, 0, &vib)) - return IMGTOOLERR_READERROR; - - for (i=0; i<3; i++) - { - memcpy(vib.subdir[i].name, catalog->subdirs[i].name, 10); - set_UINT16BE(&vib.subdir[i].fdir_aphysrec, image->dsk.fdir_aphysrec[i+1]); - } - - memcpy(vib.abm, image->abm, 200); - - if (write_absolute_physrec(& image->l1_img, 0, &vib)) - return IMGTOOLERR_WRITEERROR; - } - } - else - { - catalog = &image->dsk.catalogs[parent_ref]; - - if (read_absolute_physrec(& image->l1_img, catalog->files[catalog_index].fdr_ptr, &fdr)) - return IMGTOOLERR_READERROR; - - /* free data AUs */ -// fphysrecs = - get_UINT16BE(fdr.fphysrecs); - - i = 0; - cluster_index = 0; - while (cluster_index < 76) - { - cur_AU = get_dsk_fdr_cluster_baseAU(image, & fdr, cluster_index); - if (cur_AU == 0) - /* end of cluster list */ - break; - cluster_lastfphysrec = get_dsk_fdr_cluster_lastfphysrec(& fdr, cluster_index); - - while (i<=cluster_lastfphysrec) - { - /* the condition below is an error, but it should not prevent - us from deleting the file */ - if (cur_AU >= image->AUformat.totAUs) - /*return IMGTOOLERR_CORRUPTIMAGE;*/ - break; - - image->abm[cur_AU >> 3] &= ~ (1 << (cur_AU & 7)); - - i += image->AUformat.physrecsperAU; - cur_AU++; - } - - cluster_index++; - } - /* the condition below is an error, but it should not prevent us from - deleting the file */ -#if 0 - if (ifiles[catalog_index].fdr_ptr / image->AUformat.physrecsperAU; - image->abm[cur_AU >> 3] &= ~ (1 << (cur_AU & 7)); - - /* delete catalog entry */ - for (i=catalog_index; i<127; i++) - catalog->files[i] = catalog->files[i+1]; - catalog->files[127].fdr_ptr = 0; - catalog->num_files--; - - /* update parent fdir */ - for (i=0; i<128; i++) - { - buf[2*i] = catalog->files[i].fdr_ptr >> 8; - buf[2*i+1] = catalog->files[i].fdr_ptr & 0xff; - } - if (write_absolute_physrec(& image->l1_img, image->dsk.fdir_aphysrec[parent_ref], buf)) - return IMGTOOLERR_WRITEERROR; - - /* update bitmap */ - { - dsk_vib vib; - - if (read_absolute_physrec(& image->l1_img, 0, &vib)) - return IMGTOOLERR_READERROR; - memcpy(vib.abm, image->abm, 200); - if (write_absolute_physrec(& image->l1_img, 0, &vib)) - return IMGTOOLERR_WRITEERROR; - } - } - - return (imgtoolerr_t)0; -} - -static imgtoolerr_t win_image_deletefile(imgtool::partition &partition, const char *fpath) -{ - imgtool::image &img(partition.image()); - struct ti99_lvl2_imgref *image = get_lvl2_imgref(img); - int parent_ddr_AU, is_dir, catalog_index; - win_fdr fdr; - int i; - unsigned cur_AU, end_AU; - unsigned curfdr_aphysrec; - unsigned cursibFDR_index, endsibFDR_index = 0; - int errorcode; - uint8_t buf[256]; - ti99_catalog catalog; - - - if (check_fpath(fpath)) - return (imgtoolerr_t)IMGTOOLERR_BADFILENAME; - - errorcode = win_find_catalog_entry(image, fpath, NULL, &parent_ddr_AU, &catalog, &is_dir, &catalog_index); - if (errorcode) - return (imgtoolerr_t)errorcode; - - if (is_dir) - { - unsigned DDR_AU; - win_vib_ddr ddr_buf; - - /* Read DDR record */ - DDR_AU = catalog.subdirs[catalog_index].dir_ptr; - if (read_absolute_physrec(& image->l1_img, DDR_AU*image->AUformat.physrecsperAU, &ddr_buf)) - return (imgtoolerr_t)IMGTOOLERR_READERROR; - - /* read FDIR AU pointer */ - cur_AU = get_UINT16BE(ddr_buf.fdir_AU); - - /* sanity checks */ - if ((ddr_buf.num_files > 127) || (ddr_buf.num_subdirs > 114) || (cur_AU > image->AUformat.totAUs)) - return (imgtoolerr_t)IMGTOOLERR_CORRUPTIMAGE; - - if ((ddr_buf.num_files != 0) || (ddr_buf.num_subdirs != 0)) - return (imgtoolerr_t)IMGTOOLERR_UNIMPLEMENTED; - - /* free fdir AU */ - image->abm[cur_AU >> 3] &= ~ (1 << (cur_AU & 7)); - - /* free ddr AU */ - image->abm[DDR_AU >> 3] &= ~ (1 << (DDR_AU & 7)); - - /* delete parent catalog entry */ - for (i=catalog_index; i<113; i++) - catalog.subdirs[i] = catalog.subdirs[i+1]; - catalog.subdirs[113].dir_ptr = 0; - catalog.num_subdirs--; - - /* update parent VIB/DDR */ - if (read_absolute_physrec(& image->l1_img, parent_ddr_AU * image->AUformat.physrecsperAU, &ddr_buf)) - return (imgtoolerr_t)IMGTOOLERR_READERROR; - ddr_buf.num_subdirs = catalog.num_subdirs; - for (i=0; i<114; i++) - set_UINT16BE(&ddr_buf.subdir_AU[i], catalog.subdirs[i].dir_ptr); - if (write_absolute_physrec(& image->l1_img, parent_ddr_AU * image->AUformat.physrecsperAU, &ddr_buf)) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - - /* save allocation bitmap (aphysrecs 1 through n, n<=33) */ - for (i=0; i < (image->AUformat.totAUs+2047)/2048; i++) - if (write_absolute_physrec(&image->l1_img, i+1, image->abm+i*256)) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - } - else - { - /* 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 explicitly */ - { - int pastendoflist_flag; - unsigned prevfdr_aphysrec; - - - pastendoflist_flag = 0; - cursibFDR_index = 0; - curfdr_aphysrec = catalog.files[catalog_index].fdr_ptr * image->AUformat.physrecsperAU; - if (read_absolute_physrec(& image->l1_img, curfdr_aphysrec, &fdr)) - return (imgtoolerr_t)IMGTOOLERR_READERROR; - - if (get_UINT16BE(fdr.prevsibFDR_AU) != 0) - return (imgtoolerr_t)IMGTOOLERR_CORRUPTIMAGE; - - while (1) - { - if (! pastendoflist_flag) - { - /* look for end of list */ - for (i=0; i<54; i++) - { - if (get_UINT16BE(fdr.clusters[i][0]) == 0) - { - endsibFDR_index = cursibFDR_index; - pastendoflist_flag = true; - break; - } - } - } - - /* exit loop if end of sibling chain */ - if (! get_UINT16BE(fdr.nextsibFDR_AU)) - break; - - /* otherwise read next FDR */ - if (get_UINT16BE(fdr.nextsibFDR_AU) >= image->AUformat.totAUs) - return (imgtoolerr_t)IMGTOOLERR_CORRUPTIMAGE; - - prevfdr_aphysrec = curfdr_aphysrec; - curfdr_aphysrec = get_win_fdr_nextsibFDR_aphysrec(image, &fdr); - if (read_absolute_physrec(& image->l1_img, curfdr_aphysrec, &fdr)) - return (imgtoolerr_t)IMGTOOLERR_READERROR; - cursibFDR_index++; - - /* check that back chaining is consistent with forward chaining */ - if (get_win_fdr_prevsibFDR_aphysrec(image, &fdr) != prevfdr_aphysrec) - return (imgtoolerr_t)IMGTOOLERR_CORRUPTIMAGE; - } - if (! pastendoflist_flag) - endsibFDR_index = cursibFDR_index; - } - - - while (1) - { - if (cursibFDR_index <= endsibFDR_index) - { - for (i = 0; i < 54; i++) - { - cur_AU = get_UINT16BE(fdr.clusters[i][0]); - if (cur_AU == 0) - /* end of cluster list */ - break; - end_AU = get_UINT16BE(fdr.clusters[i][1]); - - while (cur_AU<=end_AU) - { - /* the condition below is an error, but it should not prevent - us from deleting the file */ - if (cur_AU >= image->AUformat.totAUs) - /*return IMGTOOLERR_CORRUPTIMAGE;*/ - break; - - image->abm[cur_AU >> 3] &= ~ (1 << (cur_AU & 7)); - - cur_AU++; - } - } - } - - /* free fdr AU if applicable */ - if ((curfdr_aphysrec % image->AUformat.physrecsperAU) == 0) - { - cur_AU = curfdr_aphysrec / image->AUformat.physrecsperAU; - image->abm[cur_AU >> 3] &= ~ (1 << (cur_AU & 7)); - } - - if (cursibFDR_index == 0) - break; - curfdr_aphysrec = get_win_fdr_prevsibFDR_aphysrec(image, &fdr); - if (read_absolute_physrec(& image->l1_img, curfdr_aphysrec, &fdr)) - return (imgtoolerr_t)IMGTOOLERR_READERROR; - cursibFDR_index--; - } - - - /* delete catalog entry */ - for (i=catalog_index; i<127; i++) - catalog.files[i] = catalog.files[i+1]; - catalog.files[127].fdr_ptr = 0; - catalog.num_files--; - - - /* update VIB/DDR and get FDIR AU address */ - { - win_vib_ddr parent_ddr; - - if (read_absolute_physrec(& image->l1_img, parent_ddr_AU * image->AUformat.physrecsperAU, &parent_ddr)) - return (imgtoolerr_t)IMGTOOLERR_READERROR; - parent_ddr.num_files = catalog.num_files; - if (write_absolute_physrec(& image->l1_img, parent_ddr_AU * image->AUformat.physrecsperAU, &parent_ddr)) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - cur_AU = get_UINT16BE(parent_ddr.fdir_AU); - } - - /* generate FDIR and save it */ - for (i=0; i<127; i++) - { - buf[2*i] = catalog.files[i].fdr_ptr >> 8; - buf[2*i+1] = catalog.files[i].fdr_ptr & 0xff; - } - buf[254] = parent_ddr_AU >> 8; - buf[255] = parent_ddr_AU & 0xff; - if (write_absolute_physrec(& image->l1_img, cur_AU * image->AUformat.physrecsperAU, buf)) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - - /* save allocation bitmap (aphysrecs 1 through n, n<=33) */ - for (i=0; i < (image->AUformat.totAUs+2047)/2048; i++) - if (write_absolute_physrec(&image->l1_img, i+1, image->abm+i*256)) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - } - - return (imgtoolerr_t)0; -} - -/* - Create a blank ti99_image (common code). - - Supports MESS and V9T9 formats only -*/ -static imgtoolerr_t dsk_image_create(imgtool::image &image, imgtool::stream::ptr &&stream, util::option_resolution *createoptions, ti99_img_format img_format) -{ - const char *volname; - int density; - ti99_lvl1_imgref l1_img; - int protected_var; - - int totphysrecs, physrecsperAU, totAUs; - - dsk_vib vib; - uint8_t empty_sec[256]; - - int i; - - l1_img.img_format = img_format; - l1_img.file_handle = stream.get(); // can't release here - - /* read options */ - volname = createoptions->lookup_string(dsk_createopts_volname).c_str(); - l1_img.geometry.heads = createoptions->lookup_int(dsk_createopts_sides); - l1_img.geometry.cylinders = createoptions->lookup_int(dsk_createopts_tracks); - l1_img.geometry.secspertrack = createoptions->lookup_int(dsk_createopts_sectors); - protected_var = createoptions->lookup_int(dsk_createopts_protection); - density = createoptions->lookup_int(dsk_createopts_density); - - /* NPW 03-DEC-2003 - Fixes a crash if volname is NULL */ - if (!volname) - volname = ""; - - totphysrecs = l1_img.geometry.secspertrack * l1_img.geometry.cylinders * l1_img.geometry.heads; - physrecsperAU = (totphysrecs + 1599) / 1600; - /* round to next larger power of 2 */ - for (i = 1; i < physrecsperAU; i <<= 1) - ; - physrecsperAU = i; - totAUs = totphysrecs / physrecsperAU; - - /* auto-density */ - if (density == 0) - { - if (l1_img.geometry.secspertrack <= 9) - density = 1; - else if (l1_img.geometry.secspertrack <= 18) - density = 2; - else - density = 3; - } - - /* check volume name */ - if (strchr(volname, '.') || strchr(volname, ' ') || (strlen(volname) > 10)) - return /*IMGTOOLERR_BADFILENAME*/IMGTOOLERR_PARAMCORRUPT; - - /* FM disks can hold fewer sector per track than MFM disks */ - if ((density == 1) && (l1_img.geometry.secspertrack > 9)) - return IMGTOOLERR_PARAMTOOLARGE; - - /* DD disks can hold fewer sector per track than HD disks */ - if ((density == 2) && (l1_img.geometry.secspertrack > 18)) - return IMGTOOLERR_PARAMTOOLARGE; - - /* check total disk size */ - if (totphysrecs < 2) - return IMGTOOLERR_PARAMTOOSMALL; - - /* initialize vib in aphysrec 0 */ - - /* set volume name */ - str_to_fname(vib.name, volname); - - /* set every header field */ - set_UINT16BE(& vib.totphysrecs, totphysrecs); - vib.secspertrack = l1_img.geometry.secspertrack; - vib.id[0] = 'D'; - vib.id[1] = 'S'; - vib.id[2] = 'K'; - vib.protection = protected_var ? 'P' : ' '; - vib.cylinders = l1_img.geometry.cylinders; - vib.heads = l1_img.geometry.heads; - vib.density = density; - for (i=0; i<3; i++) - { - memset(vib.subdir[i].name, '\0', 10); - set_UINT16BE(& vib.subdir[i].fdir_aphysrec, 0); - } - - /* clear bitmap */ - for (i=0; i < (totAUs>>3); i++) - vib.abm[i] = 0; - - if (totAUs & 7) - { - vib.abm[i] = 0xff << (totAUs & 7); - i++; - } - - for (; i < 200; i++) - vib.abm[i] = 0xff; - - /* mark first 2 aphysrecs (vib and fdir) as used */ - vib.abm[0] |= (physrecsperAU == 1) ? 3 : 1; - - /* write aphysrec 0 */ - if (write_absolute_physrec(&l1_img, 0, &vib)) - return IMGTOOLERR_WRITEERROR; - - - /* now clear every other physrecs, including the FDIR record */ - memset(empty_sec, 0, sizeof(empty_sec)); - - for (i=1; i -#include -#include -#include - -/* 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. */ -/* I chose a limit of 512. No need to use more until someone creates CD-ROMs -for TI990. */ -#define MAX_SECTOR_SIZE 512 -#define MIN_SECTOR_SIZE 256 - -#define MAX_CYLINDERS 2047 -#define MAX_HEADS 31 -#define MAX_SECTORS_PER_TRACK 256 /* 255 for 512-byte-long sector, so that the total number of words that can be recorded on a track may fit in one 16-bit word (store registers command) */ - -/* Max path len in chars: this value is 48 characters in DX10, but since the -path includes at least a leading '.', our value is 47. */ -/* Since path generally include a volume name that can be up to 8 character -long, we should display a warning message when the user wants to create a path -that is longer than 39 characters. */ -#define MAX_PATH_LEN 47 -#define MAX_SAFE_PATH_LEN 39 - -#define MAX_DIR_LEVEL 25 /* We need to put a recursion limit to avoid endless recursion hazard */ - - -struct UINT16BE -{ - uint8_t bytes[2]; -}; - -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; -} - -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; -} - -/* - disk image header -*/ -struct disk_image_header -{ - UINT32BE cylinders; /* number of cylinders on hard disk (big-endian) */ - UINT32BE heads; /* number of heads on hard disk (big-endian) */ - UINT32BE sectors_per_track; /* number of sectors per track on hard disk (big-endian) */ - UINT32BE bytes_per_sector; /* number of bytes of data per sector on hard disk (big-endian) */ -}; - -enum -{ - header_len = sizeof(disk_image_header) -}; - -/* - Disk structure: - - Track 0 Sector 0: see below - Track 0 Sector 1: list of bad ADU - Track 0 Sector 2 through N: disk allocation bitmap - 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 diagnostic information (reported as .S$DIAG) - Remaining sectors are used for fdr and data. -*/ - -/* - SC0 record (Disk sector 0) -*/ -struct ti990_sc0 -{ - char vnm[8]; /* volume name */ - UINT16BE tna; /* total number of ADUs */ - uint8_t sbm; /* starting sector of bit maps */ - uint8_t tbm; /* total bit maps */ - UINT16BE rl; /* track 01 record length */ - UINT16BE slt; /* system loader track address */ - uint8_t fill00[6]; /* * * RESERVED * * */ - UINT16BE nba; /* total number of bad ADUs on disk */ - UINT16BE sle; /* system loader entry point */ - UINT16BE sll; /* system loader length */ - uint8_t fill01[8]; /* * * RESERVED * * */ - UINT16BE lt1; /* system loader track (copy 2) */ - uint8_t fill02[8]; /* * * RESERVED * * */ - char pi1[8]; /* primary system file name */ - char pi2[8]; /* secondary system file name */ - UINT16BE pif; /* system selector */ - UINT16BE vda; /* volume directory ADU */ - UINT16BE vpl; /* vcatalog physical record length */ - UINT16BE spa; /* sectors per ADU */ - uint8_t dcd[4]; /* disk creation date */ - char pf1[8]; /* primary program file */ - char pf2[8]; /* secondary program file */ - UINT16BE pff; /* program file switch */ - char of1[8]; /* primary overlay file */ - char of2[8]; /* secondary overlay file */ - UINT16BE off; /* overlay file switch */ - char il1[8]; /* primary intermediate loader */ - char il2[8]; /* secondary intermediate loader */ - UINT16BE ilf; /* intermediate loader flag */ - char din[8]; /* diagnostic file name */ - UINT16BE dif; /* diagnostic flag */ - UINT16BE drs; /* default physical record size "DBUILD DETERMINES DEFAULT PRS" (whatever it means) */ - UINT16BE bal; /* starting sector of bad ADU list */ - UINT16BE spr; /* track 0 sectors per record */ - char wf1[8]; /* WCS primary microcode file */ - char wf2[8]; /* WCS secondary microcode file */ - UINT16BE wff; /* WCS flag switch */ - UINT16BE vif; /* track 1 select flag (whatever it means) volume information copied flag */ - UINT16BE sta; /* state of disk: */ - /* 1 = disk surface has not been tested for defects */ - /* 2 = disk surface has been tested, but no file system has been installed */ - /* 3 = a file system has been installed */ - UINT16BE dct; /* disk creation time */ - UINT16BE fsf; /* * * RESERVED * * */ - /* SCOSIZ = >AA */ -}; - -/* - DOR (Directory Overhead Record) -*/ -struct ti990_dor -{ - UINT16BE nrc; /* # records in directory (minus DOR) nrc = nfl + nar (+ tfc???) */ - UINT16BE nfl; /* # files currently in directory */ - UINT16BE nar; /* # of available records */ - UINT16BE tfc; /* number of temporary files */ - char dnm[8]; /* directory file name (VCATALOG for root) */ - UINT16BE lvl; /* level # of directory (0 for root, 1 for children of root, 2 for grandchildren, etc) */ - char pnm[8]; /* name of parent directory (VCATALOG for root, even though it makes little sense) */ - UINT16BE prs; /* "default physical record length (used for file creation)" */ - /* DORSIZ = >1C */ -}; - -/* - file flags found in fdr -*/ -enum -{ - ace_flg_rdf = 0x8000, /* read access flag */ - ace_flg_wrf = 0x4000, /* write access flag */ - ace_flg_dlf = 0x2000, /* delete access flag */ - ace_flg_exf = 0x1000, /* execute access flag */ - ace_flg_ctf = 0x0800, /* control access flag */ - - fdr_fl1_sec = 0x8000, /* file secured flag */ - - fdr_flg_fu = 0xc000, /* file usage bits */ - fdr_flg_fu_shift = 14, - fdr_flg_fmt = 0x3000, /* file format bits */ - fdr_flg_fmt_shift = 12, - fdr_flg_all = 0x0800, /* extendable file flag */ - fdr_flg_ft = 0x0600, /* file type bits */ - fdr_flg_ft_shift = 9, - fdr_flg_wpb = 0x0100, /* write protect bit */ - fdr_flg_dpb = 0x0080, /* delete protect bit */ - fdr_flg_tmp = 0x0040, /* temporary file flag */ - fdr_flg_blb = 0x0020, /* blocked file flag */ - fdr_flg_ali = 0x0010, /* alias flag bit */ - fdr_flg_fwt = 0x0008, /* forced write / partial logging */ - fdr_flg_cdr = 0x0001 /* record is CDR */ -}; - -/* - ACE subrecord found in FDR -*/ -struct ti990_ace -{ - char agn[8]; /* access group name */ - UINT16BE flg; /* flags */ -}; - -/* - FDR record -*/ -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 */ - UINT16BE fl1; /* flags word 1 */ - UINT16BE flg; /* flags word 2 */ - UINT16BE prs; /* physical record size */ - UINT16BE lrs; /* logical record size */ - UINT16BE pas; /* primary allocation size: # of ADUs allocated in primary allocation block? */ - UINT16BE paa; /* primary allocation address: first ADU of primary allocation block? */ - UINT16BE sas; /* secondary allocation size: used to determinate the # of blocks allocated per secondary allocation */ - UINT16BE saa; /* offset of secondary table: ???? "offset into this FDR of the secondary allocation table, if any. No secondary allocation table is denoted by 0. Secondary allocations are present only for unbounded files." */ - UINT16BE rfa; /* record number of first alias */ - UINT32BE eom; /* end of medium record number */ - UINT32BE bkm; /* end of medium block number */ - UINT16BE ofm; /* end of medium offset / */ - /* 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; /* 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) */ - 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 */ -}; - -/* - ADR record: variant of FDR for Aliases - - The fields marked here with *** are in the ADR template to maintain - compatibility with the FDR template. -*/ -struct ti990_adr -{ - UINT16BE hkc; /* hask key count */ - UINT16BE hkv; /* hask key value */ - char fnm[8]; /* file name */ - char psw[4]; /* "password" (whatever it means) */ - UINT16BE flg; /* flags (same as fdr.flg) */ - UINT16BE fill00; /* *** physical record size */ - UINT16BE fill01; /* *** logical record size */ - UINT16BE fill02; /* *** primary allocation size */ - UINT16BE fill03; /* *** primary allocation address */ - UINT16BE fill04; /* *** secondary allocation size */ - UINT16BE fill05; /* *** secondary allocation address */ - UINT16BE rna; /* record number of next ADR */ - UINT16BE raf; /* record # of actual FDR (from 1 through dor.nrc) */ -}; - -/* - CDR record: variant of FDR for Channel - - The CDR is the permanent record of a channel. It is carried as an alias - of the program file in which the channel owner task resides. -*/ -struct ti990_cdr -{ - UINT16BE hkc; /* hask key count */ - UINT16BE hkv; /* hask key value */ - char fnm[8]; /* file name */ - 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 */ - UINT16BE mxl; /* maximum message length */ - 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 */ - 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 */ -}; - -/* - Based on contents of the flags field, catalog entries may be either an FDR, - an ADR or a CDR. - - They may be a KDR, too, but confusion is impossible because the KDR FILL00 - field starts at offset 4, and therefore if we try to interpret a KDR as an - FDR (or ADR, CDR), we will find fnm[0] and assume the FDR is empty. -*/ -union directory_entry -{ - ti990_fdr fdr; - ti990_adr adr; - ti990_cdr cdr; -}; - -#if 0 - -/* - tifile header: stand-alone file -*/ -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 */ -}; - -/* - catalog entry (used for in-memory catalog) -*/ -struct catalog_entry -{ - uint16_t fdr_secnum; - char filename[10]; -}; - -#endif - -/* - Disk geometry -*/ -struct ti990_geometry -{ - unsigned int cylinders, heads, sectors_per_track, bytes_per_sector; -}; - -/* - Physical sector address -*/ -struct ti990_phys_sec_address -{ - int cylinder; - int head; - int sector; -}; - -/* - ti99 disk image descriptor -*/ -struct ti990_image -{ - imgtool::stream *file_handle; /* imgtool file handle */ - ti990_geometry geometry; /* geometry */ - ti990_sc0 sec0; /* cached copy of sector 0 */ -}; - -/* - ti990 catalog iterator, used when imgtool reads the catalog -*/ -struct ti990_iterator -{ - ti990_image *image; - int level; /* current recursion level */ - int nrc[MAX_DIR_LEVEL]; /* length of disk catalogs in records */ - int index[MAX_DIR_LEVEL]; /* current index in the disk catalog */ - directory_entry xdr[MAX_DIR_LEVEL]; /* fdr records */ -}; - -static ti990_image *get_ti990_image(imgtool::image &image) -{ - return (ti990_image *)image.extra_bytes(); -} - - -static imgtoolerr_t ti990_image_init(imgtool::image &img, imgtool::stream::ptr &&stream); -static void ti990_image_exit(imgtool::image &img); -static void ti990_image_info(imgtool::image &img, std::ostream &stream); -static imgtoolerr_t ti990_image_beginenum(imgtool::directory &enumeration, const char *path); -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 -static imgtoolerr_t ti990_image_create(imgtool::image &image, imgtool::stream::ptr &&stream, util::option_resolution *createoptions); - -enum -{ - /*ti990_createopts_volname = 'A',*/ - ti990_createopts_cylinders = 'B', - ti990_createopts_heads = 'C', - ti990_createopts_sectors = 'D', - ti990_createopts_sectorsize = 'E' -}; - -OPTION_GUIDE_START( ti990_create_optionguide ) - /*OPTION_STRING(ti990_createopts_volname, "label", "Volume name" )*/ - OPTION_INT(ti990_createopts_cylinders, "cylinders", "Cylinders" ) - OPTION_INT(ti990_createopts_heads, "heads", "Heads" ) - OPTION_INT(ti990_createopts_sectors, "sectors", "Sectors" ) - OPTION_INT(ti990_createopts_sectorsize, "bytes per sector (typically 256)", "Bytes Per Sector" ) -OPTION_GUIDE_END - -#define symb2str2(a) #a -#define symb2str(a) symb2str2(a) -#define ti990_create_optionspecs "B1-[145]-" symb2str(MAX_CYLINDERS)";C1-[4]-" symb2str(MAX_HEADS)";D1-[32]-" symb2str(MAX_SECTORS_PER_TRACK)";E" symb2str(MIN_SECTOR_SIZE)"-[256]-" symb2str(MAX_SECTOR_SIZE)";" - -void ti990_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info) -{ - switch(state) - { - case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "ti990hd"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "TI990 Hard Disk"); break; - case IMGTOOLINFO_STR_FILE_EXTENSIONS: strcpy(info->s = imgtool_temp_str(), "hd"); break; - case IMGTOOLINFO_STR_EOLN: /* strcpy(info->s = imgtool_temp_str(), "\r"); */ break; - - case IMGTOOLINFO_PTR_OPEN: info->open = ti990_image_init; break; - case IMGTOOLINFO_PTR_CLOSE: info->close = ti990_image_exit; break; - case IMGTOOLINFO_PTR_INFO: info->info = ti990_image_info; break; - case IMGTOOLINFO_PTR_BEGIN_ENUM: info->begin_enum = ti990_image_beginenum; break; - case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = ti990_image_nextenum; break; - case IMGTOOLINFO_PTR_CLOSE_ENUM: info->close_enum = ti990_image_closeenum; break; - case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = ti990_image_freespace; break; - case IMGTOOLINFO_PTR_READ_FILE: /* info->read_file = ti990_image_readfile; */ break; - case IMGTOOLINFO_PTR_WRITE_FILE: /* info->write_file = ti990_image_writefile; */ break; - case IMGTOOLINFO_PTR_DELETE_FILE: /* info->delete_file = ti990_image_deletefile; */ break; - case IMGTOOLINFO_PTR_CREATE: info->create = ti990_image_create; break; - - case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE: info->createimage_optguide = &ti990_create_optionguide; break; - case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC: strcpy(info->s = imgtool_temp_str(), ti990_create_optionspecs); break; - } -} - -#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) -{ - int i; - - - i = 0; - - /* copy 8 characters at most */ - if (src) - while ((i<8) && (src[i]!='\0')) - { - dst[i] = src[i]; - i++; - } - - /* pad with spaces */ - while (i<8) - { - dst[i] = ' '; - i++; - } -} -#endif - -/* - Convert a 8-character file name to a C string (removing trailing spaces if necessary) -*/ -static void fname_to_str(char *dst, const char src[8], int n) -{ - int i; - int last_nonspace; - - - /* copy 8 characters at most */ - if (--n > 8) - n = 8; - - /* copy filename */ - i = 0; - last_nonspace = -1; - - while (icylinder*geometry->heads) + address->head)*geometry->sectors_per_track + address->sector)*geometry->bytes_per_sector + header_len; - - return offset; -} - -/* - Read one sector from a disk image - - file_handle: imgtool file handle - address: physical sector address - geometry: disk geometry (sectors per track, tracks per side, sides) - dest: pointer to destination buffer - len: length of data to read -*/ -static int read_sector_physical_len(imgtool::stream &file_handle, const ti990_phys_sec_address *address, const ti990_geometry *geometry, void *dest, int len) -{ - int reply; - - if (len > geometry->bytes_per_sector) - return 1; - - /* seek to sector */ - reply = file_handle.seek(phys_address_to_offset(address, geometry), SEEK_SET); - if (reply) - return 1; - /* read it */ - reply = file_handle.read(dest, len); - if (reply != len) - return 1; - - return 0; -} - -#ifdef UNUSED_FUNCTION -/* - Read one sector from a disk image - - file_handle: imgtool file handle - address: physical sector address - 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) -{ - return read_sector_physical_len(file_handle, address, geometry, dest, geometry->bytes_per_sector); -} -#endif - -/* - Write one sector to a disk image - - file_handle: imgtool file handle - address: physical sector address - geometry: disk geometry (sectors per track, tracks per side, sides) - src: pointer to source buffer - len: length of source buffer -*/ -static int write_sector_physical_len(imgtool::stream &file_handle, const ti990_phys_sec_address *address, const ti990_geometry *geometry, const void *src, int len) -{ - int reply; - - if (len > geometry->bytes_per_sector) - return 1; - - /* seek to sector */ - reply = file_handle.seek(phys_address_to_offset(address, geometry), SEEK_SET); - if (reply) - return 1; - /* write it */ - reply = file_handle.write(src, len); - if (reply != len) - return 1; - /* pad with 0s if needed */ - if (len < geometry->bytes_per_sector) - { - reply = file_handle.fill(0, geometry->bytes_per_sector - len); - - if (reply != geometry->bytes_per_sector - len) - return 1; - } - - return 0; -} - -#ifdef UNUSED_FUNCTION -/* - Write one sector to a disk image - - file_handle: imgtool file handle - address: physical sector address - 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) -{ - return write_sector_physical_len(file_handle, address, geometry, src, geometry->bytes_per_sector); -} -#endif - -/* - Convert logical sector address to physical sector address -*/ -static void log_address_to_phys_address(int secnum, const ti990_geometry *geometry, ti990_phys_sec_address *address) -{ - address->sector = secnum % geometry->sectors_per_track; - secnum /= geometry->sectors_per_track; - address->head = secnum % geometry->heads; - address->cylinder = secnum / geometry->heads; -} - -/* - Read one sector from a disk image - - file_handle: imgtool file handle - secnum: logical sector address - geometry: disk geometry (sectors per track, tracks per side, sides) - dest: pointer to destination buffer - len: length of data to read -*/ -static int read_sector_logical_len(imgtool::stream &file_handle, int secnum, const ti990_geometry *geometry, void *dest, int len) -{ - ti990_phys_sec_address address; - - - log_address_to_phys_address(secnum, geometry, &address); - - return read_sector_physical_len(file_handle, &address, geometry, dest, len); -} - -#ifdef UNUSED_FUNCTION -/* - Read one sector from a disk image - - file_handle: imgtool file handle - secnum: logical sector address - 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) -{ - return read_sector_logical_len(file_handle, secnum, geometry, dest, geometry->bytes_per_sector); -} -#endif - -/* - Write one sector to a disk image - - file_handle: imgtool file handle - secnum: logical sector address - geometry: disk geometry (sectors per track, tracks per side, sides) - src: pointer to source buffer - len: length of source buffer -*/ -static int write_sector_logical_len(imgtool::stream &file_handle, int secnum, const ti990_geometry *geometry, const void *src, int len) -{ - ti990_phys_sec_address address; - - - log_address_to_phys_address(secnum, geometry, &address); - - return write_sector_physical_len(file_handle, &address, geometry, src, len); -} - -/* - Write one sector to a disk image - - file_handle: imgtool file handle - secnum: logical sector address - 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_logical(imgtool::stream &file_handle, int secnum, const ti990_geometry *geometry, const void *src) -{ - return write_sector_logical_len(file_handle, secnum, geometry, src, geometry->bytes_per_sector); -} - -#if 0 -#pragma mark - -#pragma mark CATALOG FILE ROUTINES -#endif - -#ifdef UNUSED_FUNCTION -/* - Find the catalog entry and fdr record associated with a file name - - image: ti990_image image record - fpath: path of the file to search - fdr: pointer to buffer where the fdr record should be stored (may be NULL) - catalog_index: on output, index of file catalog entry (may be NULL) - out_fdr_secnum: on output, sector address of the fdr (may be NULL) - 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) -{ - int fdr_secnum = -1, parent_fdr_secnum; - int i; - const char *element_start, *element_end; - int element_len; - char element[8]; - ti990_dor dor; - directory_entry xdr; - int hash_key; - int nrc; - unsigned base; - int reply; - int flag; - - - base = (unsigned) get_UINT16BE(image->sec0.vda) * get_UINT16BE(image->sec0.spa); - - element_start = fpath; - do - { - /* read directory header */ - reply = read_sector_logical_len(image->file_handle, base, & image->geometry, &dor, sizeof(dor)); - if (reply) - return IMGTOOLERR_READERROR; - - nrc = get_UINT16BE(dor.nrc); - - /* find next path element */ - element_end = strchr(element_start, '.'); - element_len = element_end ? (element_end - element_start) : strlen(element_start); - if ((element_len > 8) || (element_len == 0)) - return IMGTOOLERR_BADFILENAME; - /* generate file name and hash key */ - hash_key = 1; - for (i=0; ifile_handle, base + i, & image->geometry, - & xdr, 0x86); - if (reply) - return IMGTOOLERR_READERROR; - if (!memcmp(element, xdr.fdr.fnm, 8)) - { /* found match !!! */ - parent_fdr_secnum = fdr_secnum; - fdr_secnum = base + i; - break; - } - - /* next record */ - if (i != nrc) - i++; - else - i = 1; - - /* exit if we have tested every record */ - if (i == hash_key) - return IMGTOOLERR_FILENOTFOUND; - } - - /* iterate */ - if (element_end) - { - element_start = element_end+1; - /* we need to check that this is a directory */ - /* if it is an alias to a directory, we need to follow it, too. */ - - /* parse flags */ - flag = get_UINT16BE(xdr.fdr.flg); - - if (flag & fdr_flg_ali) - { - /* read original fdr */ - reply = read_sector_logical_len(image->file_handle, base + get_UINT16BE(xdr.adr.raf), - & image->geometry, & xdr, 0x86); - - flag = get_UINT16BE(xdr.fdr.flg); - } - - if (flag & fdr_flg_cdr) - /* This is a channel, not a file */ - return IMGTOOLERR_BADFILENAME; - else if (flag & fdr_flg_ali) - /* WTH??? */ - return IMGTOOLERR_CORRUPTIMAGE; - else if (((flag >> fdr_flg_fu_shift) & 3) != 1) - { - /* This file is not a directory */ - return IMGTOOLERR_BADFILENAME; - } - - /* initialize base */ - base = (unsigned) get_UINT16BE(xdr.fdr.paa) * get_UINT16BE(image->sec0.spa); - } - else - element_start = NULL; - } - while (element_start); - - if (catalog_index) - *catalog_index = i; - - if (out_fdr_secnum) - *out_fdr_secnum = fdr_secnum; - - if (out_parent_fdr_secnum) - *out_parent_fdr_secnum = parent_fdr_secnum; - - return 0; -} -#endif - -#if 0 -/* - Allocate one sector on disk, for use as a fdr record - - image: ti99_image image record - fdr_secnum: on output, logical address of a free sector -*/ -static int alloc_fdr_sector(ti99_image *image, int *fdr_secnum) -{ - int totsecs = (image->sec0.totsecsMSB << 8) | image->sec0.totsecsLSB; - int i; - - - for (i=0; isec0.abm[i >> 3] & (1 << (i & 7)))) - { - *fdr_secnum = i; - image->sec0.abm[i >> 3] |= 1 << (i & 7); - - return 0; - } - } - - return IMGTOOLERR_NOSPACE; -} - -/* - Extend a file with nb_alloc_sectors extra sectors - - image: ti99_image image record - fdr: file fdr record - nb_alloc_sectors: number of sectors to allocate -*/ -static int alloc_file_sectors(ti99_image *image, ti99_fdr *fdr, int nb_alloc_sectors) -{ - int totsecs = (image->sec0.totsecsMSB << 8) | image->sec0.totsecsLSB; - int free_sectors; - int secsused; - int i; - int lnks_index; - int cur_sec, last_sec, p_last_sec; - int cur_block_len, cur_block_start; - int first_best_block_len, first_best_block_start = 0; - int second_best_block_len, second_best_block_start = 0; - int search_start; - - /* compute free space */ - free_sectors = 0; - for (i=0; isec0.abm[i >> 3] & (1 << (i & 7)))) - free_sectors++; - } - - /* check we have enough free space */ - if (free_sectors < nb_alloc_sectors) - return IMGTOOLERR_NOSPACE; - - /* current number of data sectors in file */ - secsused = get_fdr_secsused(fdr); - - if (secsused == 0) - { /* links array must be empty */ - lnks_index = 0; - } - else - { /* try to extend last block */ - last_sec = -1; - for (lnks_index=0; lnks_index<76; lnks_index++) - { - p_last_sec = last_sec; - last_sec = (fdr->lnks[lnks_index][2] << 4) | (fdr->lnks[lnks_index][1] >> 4); - if (last_sec >= (secsused-1)) - break; - } - if (lnks_index == 76) - /* that sucks */ - return IMGTOOLERR_CORRUPTIMAGE; - - if (last_sec > (secsused-1)) - { /* some extra space has already been allocated */ - cur_block_len = last_sec - (secsused-1); - if (cur_block_len > nb_alloc_sectors) - cur_block_len = nb_alloc_sectors; - - secsused += cur_block_len; - set_fdr_secsused(fdr, secsused); - nb_alloc_sectors -= cur_block_len; - if (! nb_alloc_sectors) - return 0; /* done */ - } - - /* block base */ - cur_sec = ((fdr->lnks[lnks_index][1] & 0xf) << 8) | fdr->lnks[lnks_index][0]; - /* point past block end */ - cur_sec += last_sec-p_last_sec; - /* count free sectors after last block */ - cur_block_len = 0; - for (i=cur_sec; (! (image->sec0.abm[i >> 3] & (1 << (i & 7)))) && (cur_block_len < nb_alloc_sectors) && (i < totsecs); i++) - cur_block_len++; - if (cur_block_len) - { /* extend last block */ - secsused += cur_block_len; - set_fdr_secsused(fdr, secsused); - last_sec += cur_block_len; - nb_alloc_sectors -= cur_block_len; - fdr->lnks[lnks_index][1] = (fdr->lnks[lnks_index][1] & 0x0f) | (last_sec << 4); - fdr->lnks[lnks_index][2] = last_sec >> 4; - for (i=0; isec0.abm[(i+cur_sec) >> 3] |= 1 << ((i+cur_sec) & 7); - if (! nb_alloc_sectors) - return 0; /* done */ - } - lnks_index++; - if (lnks_index == 76) - /* that sucks */ - return IMGTOOLERR_NOSPACE; - } - - search_start = image->data_offset; /* initially, search for free space only in data space */ - while (nb_alloc_sectors) - { - /* find smallest data block at least nb_alloc_sectors in length, and largest data block less than nb_alloc_sectors in length */ - first_best_block_len = INT_MAX; - second_best_block_len = 0; - for (i=search_start; isec0.abm[i >> 3] & (1 << (i & 7)))) - { /* found one free block */ - /* compute its length */ - cur_block_start = i; - cur_block_len = 0; - while ((isec0.abm[i >> 3] & (1 << (i & 7))))) - { - cur_block_len++; - i++; - } - /* compare to previous best and second-best blocks */ - if ((cur_block_len < first_best_block_len) && (cur_block_len >= nb_alloc_sectors)) - { - first_best_block_start = cur_block_start; - first_best_block_len = cur_block_len; - if (cur_block_len == nb_alloc_sectors) - /* no need to search further */ - break; - } - else if ((cur_block_len > second_best_block_len) && (cur_block_len < nb_alloc_sectors)) - { - second_best_block_start = cur_block_start; - second_best_block_len = cur_block_len; - } - } - } - - if (first_best_block_len != INT_MAX) - { /* found one contiguous block which can hold it all */ - secsused += nb_alloc_sectors; - set_fdr_secsused(fdr, secsused); - - fdr->lnks[lnks_index][0] = first_best_block_start; - fdr->lnks[lnks_index][1] = ((first_best_block_start >> 8) & 0x0f) | ((secsused-1) << 4); - fdr->lnks[lnks_index][2] = (secsused-1) >> 4; - for (i=0; isec0.abm[(i+first_best_block_start) >> 3] |= 1 << ((i+first_best_block_start) & 7); - - nb_alloc_sectors = 0; - } - else if (second_best_block_len != 0) - { /* jeez, we need to fragment it. We use the largest smaller block to limit fragmentation. */ - secsused += second_best_block_len; - set_fdr_secsused(fdr, secsused); - - fdr->lnks[lnks_index][0] = second_best_block_start; - fdr->lnks[lnks_index][1] = ((second_best_block_start >> 8) & 0x0f) | ((secsused-1) << 4); - fdr->lnks[lnks_index][2] = (secsused-1) >> 4; - for (i=0; isec0.abm[(i+second_best_block_start) >> 3] |= 1 << ((i+second_best_block_start) & 7); - - nb_alloc_sectors -= second_best_block_len; - - lnks_index++; - if (lnks_index == 76) - /* that sucks */ - return IMGTOOLERR_NOSPACE; - } - else if (search_start != 0) - { /* we did not find any free sector in the data section of the disk */ - search_start = 0; /* time to fall back to fdr space */ - } - else - return IMGTOOLERR_NOSPACE; /* This should never happen, as we pre-check that there is enough free space */ - } - - return 0; -} - -/* - Allocate a new (empty) file -*/ -static int new_file(ti99_image *image, char filename[10], int *out_fdr_secnum/*, ti99_fdr *fdr,*/) -{ - int fdr_secnum; - int catalog_index, i; - int reply = 0; - - - /* find insertion point in catalog */ - i = 0; - if ((image->catalog[0].fdr_secnum == 0) && (image->catalog[1].fdr_secnum != 0)) - i = 1; /* skip empty entry 0 (it must be a non-listable catalog) */ - - for (; (i<128) && ((fdr_secnum = image->catalog[i].fdr_secnum) != 0) && ((reply = memcmp(image->catalog[i].filename, filename, 10)) < 0); i++) - ; - - if (i == 128) - /* catalog is full */ - return IMGTOOLERR_NOSPACE; - else if (fdr_secnum && (reply == 0)) - /* file already exists */ - return IMGTOOLERR_BADFILENAME; - else - { - catalog_index = i; - reply = alloc_fdr_sector(image, &fdr_secnum); - if (reply) - return reply; - - /* look for first free entry in catalog */ - for (i=catalog_index; image->catalog[i].fdr_secnum != 0; i++) - ; - - if (i == 128) - /* catalog is full */ - return IMGTOOLERR_NOSPACE; - - /* shift catalog entries until the insertion point */ - for (/*i=127*/; i>catalog_index; i--) - image->catalog[i] = image->catalog[i-1]; - - /* write new catalog entry */ - image->catalog[catalog_index].fdr_secnum = fdr_secnum; - memcpy(image->catalog[catalog_index].filename, filename, 10); - if (out_fdr_secnum) - *out_fdr_secnum = fdr_secnum; - } - - return 0; -} - -/* - Compare two (possibly empty) catalog entry for qsort -*/ -static int qsort_catalog_compare(const void *p1, const void *p2) -{ - const catalog_entry *entry1 = p1; - const catalog_entry *entry2 = p2; - - if ((entry1->fdr_secnum == 0) && (entry2->fdr_secnum == 0)) - return 0; - else if (entry1->fdr_secnum == 0) - return +1; - else if (entry2->fdr_secnum == 0) - return -1; - else - return memcmp(entry1->filename, entry2->filename, 10); -} -#endif - -/* - Open a file as a ti990_image. -*/ -static imgtoolerr_t ti990_image_init(imgtool::image &img, imgtool::stream::ptr &&stream) -{ - ti990_image *image = get_ti990_image(img); - disk_image_header header; - int reply; - unsigned totsecs; - - image->file_handle = stream.get(); - reply = image->file_handle->read(&header, sizeof(header)); - if (reply != sizeof(header)) - return IMGTOOLERR_READERROR; - - image->geometry.cylinders = get_UINT32BE(header.cylinders); - image->geometry.heads = get_UINT32BE(header.heads); - image->geometry.sectors_per_track = get_UINT32BE(header.sectors_per_track); - image->geometry.bytes_per_sector = get_UINT32BE(header.bytes_per_sector); - - totsecs = image->geometry.cylinders*image->geometry.heads*image->geometry.sectors_per_track; - - if ((image->geometry.bytes_per_sector < MIN_SECTOR_SIZE) - || (image->geometry.bytes_per_sector > MAX_SECTOR_SIZE) - || (image->geometry.sectors_per_track > MAX_SECTORS_PER_TRACK) - || (image->geometry.heads > MAX_HEADS) - || (image->geometry.cylinders > MAX_CYLINDERS) - || (totsecs < 1) - || (image->file_handle->size() != header_len + totsecs*image->geometry.bytes_per_sector)) - { - return IMGTOOLERR_CORRUPTIMAGE; - } - - { - ti990_phys_sec_address address = { 0, 0, 0 }; - reply = read_sector_physical_len(*image->file_handle, &address, &image->geometry, & image->sec0, sizeof(image->sec0)); - } - if (reply) - { - return IMGTOOLERR_READERROR; - } - - if ((get_UINT16BE(image->sec0.tna)*get_UINT16BE(image->sec0.spa) > totsecs) - || ((get_UINT16BE(image->sec0.spa) != 1) && (get_UINT16BE(image->sec0.spa) % 3))) - { - return IMGTOOLERR_CORRUPTIMAGE; - } - - if ((get_UINT16BE(image->sec0.vpl) != 0x86) && (get_UINT16BE(image->sec0.vpl) != 0x100)) - { - return IMGTOOLERR_CORRUPTIMAGE; - } - - image->file_handle = stream.release(); - return IMGTOOLERR_SUCCESS; -} - -/* - close a ti990_image -*/ -static void ti990_image_exit(imgtool::image &img) -{ - ti990_image *image = get_ti990_image(img); - delete image->file_handle; -} - -/* - get basic information on a ti990_image - - Currently returns the volume name -*/ -static void ti990_image_info(imgtool::image &img, std::ostream &stream) -{ - ti990_image *image = get_ti990_image(img); - char vol_name[9]; - - fname_to_str(vol_name, image->sec0.vnm, 9); - - stream << vol_name; -} - -/* - Open the disk catalog for enumeration -*/ -static imgtoolerr_t ti990_image_beginenum(imgtool::directory &enumeration, const char *path) -{ - ti990_image *image = (ti990_image *) enumeration.image().extra_bytes(); - ti990_iterator *iter = (ti990_iterator *) enumeration.extra_bytes(); - ti990_dor dor; - int reply; - - iter->image = image; - - reply = read_sector_logical_len(*iter->image->file_handle, - (unsigned) get_UINT16BE(iter->image->sec0.vda) * get_UINT16BE(iter->image->sec0.spa), - & iter->image->geometry, &dor, sizeof(dor)); - - if (reply) - return IMGTOOLERR_READERROR; - - iter->level = 0; - iter->nrc[0] = get_UINT16BE(dor.nrc); - iter->index[0] = 0; - - return IMGTOOLERR_SUCCESS; -} - -/* - Enumerate disk catalog next entry -*/ -static imgtoolerr_t ti990_image_nextenum(imgtool::directory &enumeration, imgtool_dirent &ent) -{ - ti990_iterator *iter = (ti990_iterator *) enumeration.extra_bytes(); - int flag; - int reply = 0; - - - ent.corrupt = 0; - ent.eof = 0; - - while ((iter->level >= 0) - && (! (reply = read_sector_logical_len(*iter->image->file_handle, - iter->level ? (unsigned) get_UINT16BE(iter->xdr[iter->level-1].fdr.paa) * get_UINT16BE(iter->image->sec0.spa) + (iter->index[iter->level]+1) - : (unsigned) get_UINT16BE(iter->image->sec0.vda) * get_UINT16BE(iter->image->sec0.spa) + (iter->index[iter->level]+1), - & iter->image->geometry, &iter->xdr[iter->level], - iter->level ? get_UINT16BE(iter->xdr[iter->level-1].fdr.prs) - : get_UINT16BE(iter->image->sec0.vpl)))) - && (iter->xdr[iter->level].fdr.fnm[0] == 0)) - { - iter->index[iter->level]++; - while (iter->index[iter->level] >= iter->nrc[iter->level]) - iter->level--; - } - - if (iter->level < 0) - { - ent.eof = 1; - } - else if (reply) - return IMGTOOLERR_READERROR; - else - { -#if 0 - fname_to_str(ent.filename, iter->xdr[iter->level].fdr.fnm, std::size(ent.filename)); -#else - { - int i; - char buf[9]; - - ent.filename[0] = '\0'; - for (i=0; ilevel; i++) - { - fname_to_str(buf, iter->xdr[i].fdr.fnm, 9); - 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, std::size(ent.filename) - 1); - } -#endif - - /* parse flags */ - flag = get_UINT16BE(iter->xdr[iter->level].fdr.flg); - if (flag & fdr_flg_cdr) - { - snprintf(ent.attr, std::size(ent.attr), "CHANNEL"); - - ent.filesize = 0; - } - else if (flag & fdr_flg_ali) - { - ti990_fdr target_fdr; - char buf[9]; - - reply = read_sector_logical_len(*iter->image->file_handle, - iter->level ? ((unsigned) get_UINT16BE(iter->xdr[iter->level-1].fdr.paa) * get_UINT16BE(iter->image->sec0.spa) + get_UINT16BE(iter->xdr[iter->level].adr.raf)) - : ((unsigned) get_UINT16BE(iter->image->sec0.vda) * get_UINT16BE(iter->image->sec0.spa) + get_UINT16BE(iter->xdr[iter->level].adr.raf)), - & iter->image->geometry, &target_fdr, - iter->level ? get_UINT16BE(iter->xdr[iter->level-1].fdr.prs) - : get_UINT16BE(iter->image->sec0.vpl)); - - fname_to_str(buf, target_fdr.fnm, 9); - - snprintf(ent.attr, std::size(ent.attr), "ALIAS OF %s", buf); - - ent.filesize = 0; - } - else - { - const char *fmt, *type; - - switch ((flag >> fdr_flg_fmt_shift) & 3) - { - case 0: - fmt = "NBS"; - break; - case 1: - fmt = "BS "; - break; - default: - fmt = "???"; - break; - } - - switch ((flag >> fdr_flg_fu_shift) & 3) - { - case 1: - type = "DIR"; - break; - case 2: - type = "PRO"; - break; - case 3: - type = "IMG"; - break; - default: - switch ((flag >> fdr_flg_ft_shift) & 3) - { - case 1: - type = "SEQ"; - break; - case 2: - type = "REL"; - break; - case 3: - type = "KIF"; - break; - default: - type = "???"; - break; - } - break; - } - 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" : "", - (flag & fdr_flg_wpb) ? " WPT" : "", - (flag & fdr_flg_dpb) ? " DPT" : ""); - - /* len in blocks */ - ent.filesize = get_UINT32BE(iter->xdr[iter->level].fdr.bkm); - if ((((flag >> fdr_flg_ft_shift) & 3) == 3) || get_UINT16BE(iter->xdr[iter->level].fdr.ofm)) - ent.filesize++; - - /* convert to ADUs */ - if (iter->xdr[iter->level].fdr.apb > 1) - /* more than one ADU per block */ - ent.filesize *= iter->xdr[iter->level].fdr.apb; - else if (iter->xdr[iter->level].fdr.bpa > 1) - /* more than one block per ADU */ - ent.filesize = (ent.filesize + iter->xdr[iter->level].fdr.bpa - 1) / iter->xdr[iter->level].fdr.bpa; - } - iter->index[iter->level]++; - - if (get_UINT16BE(iter->xdr[iter->level].fdr.saa) != 0) - printf("roupoupou"); - else - { - int i; - for (i=0; i<64; i++) - if (iter->xdr[iter->level].fdr.sat[i]) - { - printf("roupoupou"); - break; - } - } - - /* recurse subdirectory if applicable */ - if ((((flag >> fdr_flg_fu_shift) & 3) == 1) - && (! (flag & fdr_flg_ali)) - && (! (flag & fdr_flg_cdr)) - && (iter->level < MAX_DIR_LEVEL) - && ! ((iter->level == 0) && ! memcmp(iter->xdr[iter->level].fdr.fnm, "VCATALOG", 8))) - { - ti990_dor dor; - - if (get_UINT16BE(iter->xdr[iter->level].fdr.saa) != 0) - printf("ninou"); - - read_sector_logical_len(*iter->image->file_handle, - get_UINT16BE(iter->xdr[iter->level].fdr.paa) * get_UINT16BE(iter->image->sec0.spa), - & iter->image->geometry, &dor, sizeof(dor)); - - iter->level++; - iter->nrc[iter->level] = get_UINT16BE(dor.nrc)/*get_UINT32BE(iter->fdr[iter->level-1].eom)-1*/; - iter->index[iter->level] = 0; -#if 0 - if (get_UINT16BE(dor.nrc) != (get_UINT32BE(iter->xdr[iter->level-1].fdr.eom)-1)) - printf("hiha"); -#endif - } - - /* go to upper level if applicable */ - while (iter->index[iter->level] >= iter->nrc[iter->level]) - iter->level--; - } - - return (imgtoolerr_t)0; -} - -/* - Free enumerator -*/ -static void ti990_image_closeenum(imgtool::directory &enumeration) -{ -} - -/* - Compute free space on disk image (in ADUs) -*/ -static imgtoolerr_t ti990_image_freespace(imgtool::partition &partition, uint64_t *size) -{ - imgtool::image &img(partition.image()); - ti990_image *image = get_ti990_image(img); - int totadus = get_UINT16BE(image->sec0.tna); - int adu, record, sub_adu; - char buf[256]; - size_t freeadus = 0; - - if ((totadus+2031)/2032 != image->sec0.tbm) - /*return IMGTOOLERR_CORRUPTIMAGE;*/ - return (imgtoolerr_t)0; - - adu = 0; - record = 0; - sub_adu = 0; - while (adufile_handle, image->sec0.sbm + record, &image->geometry, buf, sizeof(buf)); - - while ((adu < totadus) && (sub_adu < 2032)) - { - if (! (buf[(sub_adu >> 3) + 2] & (1 << (sub_adu & 7)))) - freeadus++; - sub_adu++; - adu++; - } - sub_adu = 0; - record++; - } - - * size = freeadus; - - 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); - int catalog_index, fdr_secnum, parent_fdr_secnum; - imgtoolerr_t reply; - - - reply = find_fdr(image, fpath, &catalog_index, &fdr_secnum, &parent_fdr_secnum); - if (reply) - return reply; - - /* ... */ - - return 0; - -#if 0 - ti99_image *image = (ti99_image*) img; - int totsecs = (image->sec0.totsecsMSB << 8) | image->sec0.totsecsLSB; - char ti_fname[10]; - ti99_fdr fdr; - tifile_header dst_header; - int i, lnks_index; - int cur_sec, last_sec; - int secsused; - uint8_t buf[256]; - int reply; - - str_to_fname(ti_fname, filename); - - reply = find_fdr(image, ti_fname, &fdr, NULL); - if (reply) - return reply; - - dst_header.tifiles[0] = '\7'; - dst_header.tifiles[1] = 'T'; - dst_header.tifiles[2] = 'I'; - dst_header.tifiles[3] = 'F'; - dst_header.tifiles[4] = 'I'; - dst_header.tifiles[5] = 'L'; - dst_header.tifiles[6] = 'E'; - dst_header.tifiles[7] = 'S'; - dst_header.secsused_MSB = fdr.secsused_MSB; - dst_header.secsused_LSB = fdr.secsused_LSB; - dst_header.flags = fdr.flags; - dst_header.recspersec = fdr.recspersec; - dst_header.eof = fdr.eof; - dst_header.reclen = fdr.reclen; - dst_header.fixrecs_MSB = fdr.fixrecs_MSB; - dst_header.fixrecs_LSB = fdr.fixrecs_LSB; - for (i=0; i<(128-14); i++) - dst_header.res[i] = 0; - - if (destf->write(& dst_header, 128) != 128) - return IMGTOOLERR_WRITEERROR; - - - secsused = get_fdr_secsused(&fdr); - - i = 0; /* file logical sector #0 */ - lnks_index = 0; /* start of file block table */ - while (i> 4); - - /* copy current file block */ - while ((i<=last_sec) && (i= totsecs) - return IMGTOOLERR_CORRUPTIMAGE; - - if (read_sector_logical(image->file_handle, cur_sec, & image->geometry, buf)) - return IMGTOOLERR_READERROR; - - if (destf->write(buf, 256) != 256) - return IMGTOOLERR_WRITEERROR; - - i++; - cur_sec++; - } - - /* next entry in file block table */ - lnks_index++; - } - - return 0; -#endif -} - -/* - Add a file to a ti990_image. -*/ -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); - int catalog_index, fdr_secnum, parent_fdr_secnum; - imgtoolerr_t reply; - - - /* check that file does not exist */ - reply = find_fdr(image, fpath, &catalog_index, &fdr_secnum, &parent_fdr_secnum); - if ((reply) && (reply != IMGTOOLERR_FILENOTFOUND)) - return reply; - - /* ... */ - - return 0; - -#if 0 - ti99_image *image = (ti99_image*) img; - int totsecs = (image->sec0.totsecsMSB << 8) | image->sec0.totsecsLSB; - char ti_fname[10]; - ti99_fdr fdr; - tifile_header src_header; - int i, lnks_index; - int cur_sec, last_sec; - int secsused; - uint8_t buf[256]; - int reply; - int fdr_secnum; - - str_to_fname(ti_fname, filename); - - reply = find_fdr(image, ti_fname, &fdr, NULL); - if (reply == 0) - { /* file already exists: causes an error for now */ - return IMGTOOLERR_UNEXPECTED; - } - else if (reply != IMGTOOLERR_FILENOTFOUND) - { - return reply; - } - - if (sourcef->read(& src_header, 128) != 128) - return IMGTOOLERR_READERROR; - - /* create new file */ - reply = new_file(image, ti_fname, &fdr_secnum); - if (reply) - return reply; - - memcpy(fdr.name, ti_fname, 10); - fdr.res10[1] = fdr.res10[0] = 0; - fdr.flags = src_header.flags; - fdr.recspersec = src_header.recspersec; - fdr.secsused_MSB = /*src_header.secsused_MSB*/0; - fdr.secsused_LSB = /*src_header.secsused_LSB*/0; - fdr.eof = src_header.eof; - fdr.reclen = src_header.reclen; - fdr.fixrecs_LSB = src_header.fixrecs_LSB; - fdr.fixrecs_MSB = src_header.fixrecs_MSB; - for (i=0; i<8; i++) - fdr.res20[i] = 0; - for (i=0; i<76; i++) - fdr.lnks[i][2] = fdr.lnks[i][1] = fdr.lnks[i][0] = 0; - - /* alloc data sectors */ - secsused = (src_header.secsused_MSB << 8) | src_header.secsused_LSB; - reply = alloc_file_sectors(image, &fdr, secsused); - if (reply) - return reply; - - /* copy data */ - i = 0; - lnks_index = 0; - while (i> 4); - - while ((i= totsecs) - return IMGTOOLERR_CORRUPTIMAGE; - - if (sourcef->read(buf, 256) != 256) - return IMGTOOLERR_READERROR; - - if (write_sector_logical(image->file_handle, cur_sec, & image->geometry, buf)) - return IMGTOOLERR_WRITEERROR; - - i++; - cur_sec++; - } - - lnks_index++; - } - - /* write fdr */ - if (write_sector_logical(image->file_handle, fdr_secnum, & image->geometry, &fdr)) - return IMGTOOLERR_WRITEERROR; - - /* update catalog */ - for (i=0; i<128; i++) - { - buf[2*i] = image->catalog[i].fdr_secnum >> 8; - buf[2*i+1] = image->catalog[i].fdr_secnum & 0xff; - } - if (write_sector_logical(image->file_handle, 1, & image->geometry, buf)) - return IMGTOOLERR_WRITEERROR; - - /* update bitmap */ - if (write_sector_logical(image->file_handle, 0, & image->geometry, &image->sec0)) - return IMGTOOLERR_WRITEERROR; - - return 0; -#endif -} - -/* - Delete a file from a ti990_image. -*/ -static imgtoolerr_t ti990_image_deletefile(imgtool::partition &partition, const char *fpath) -{ - imgtool::image *img = &partition->image(); - ti990_image *image = get_ti990_image(img); - int catalog_index, fdr_secnum, parent_fdr_secnum; - imgtoolerr_t reply; - - - reply = find_fdr(image, fpath, &catalog_index, &fdr_secnum, &parent_fdr_secnum); - if (reply) - return reply; - - /* ... */ - - return 0; - -#if 0 - ti99_image *image = (ti99_image*) img; - int totsecs = (image->sec0.totsecsMSB << 8) | image->sec0.totsecsLSB; - char ti_fname[10]; - ti99_fdr fdr; - int i, lnks_index; - int cur_sec, last_sec; - int secsused; - int catalog_index; - int reply; - uint8_t buf[256]; - - str_to_fname(ti_fname, filename); - - reply = find_fdr(image, ti_fname, &fdr, &catalog_index); - if (reply) - return reply; - - /* free data sectors */ - secsused = get_fdr_secsused(&fdr); - - i = 0; - lnks_index = 0; - while (i> 4); - - while ((i= totsecs) - return IMGTOOLERR_CORRUPTIMAGE; - - image->sec0.abm[cur_sec >> 3] &= ~ (1 << (cur_sec & 7)); - - i++; - cur_sec++; - } - - lnks_index++; - } - - /* free fdr sector */ - image->sec0.abm[image->catalog[catalog_index].fdr_secnum >> 3] &= ~ (1 << (image->catalog[catalog_index].fdr_secnum & 7)); - - /* delete catalog entry */ - for (i=catalog_index; i<127; i++) - image->catalog[i] = image->catalog[i+1]; - image->catalog[127].fdr_secnum = 0; - - /* update catalog */ - for (i=0; i<128; i++) - { - buf[2*i] = image->catalog[i].fdr_secnum >> 8; - buf[2*i+1] = image->catalog[i].fdr_secnum & 0xff; - } - if (write_sector_logical(image->file_handle, 1, & image->geometry, buf)) - return IMGTOOLERR_WRITEERROR; - - /* update bitmap */ - if (write_sector_logical(image->file_handle, 0, & image->geometry, &image->sec0)) - return IMGTOOLERR_WRITEERROR; - - return 0; -#endif -} -#endif - -/* - Create a blank ti990_image. -*/ -static imgtoolerr_t ti990_image_create(imgtool::image &image, imgtool::stream::ptr &&stream, util::option_resolution *createoptions) -{ - //const char *volname; - ti990_geometry geometry; - unsigned totsecs; - disk_image_header header; - ti990_sc0 sec0; - uint8_t empty_sec[MAX_SECTOR_SIZE]; - int reply; - int i; - - /* read options */ - //volname = createoptions->lookup_string(ti990_createopts_volname); - geometry.cylinders = createoptions->lookup_int(ti990_createopts_cylinders); - geometry.heads = createoptions->lookup_int(ti990_createopts_heads); - geometry.sectors_per_track = createoptions->lookup_int(ti990_createopts_sectors); - geometry.bytes_per_sector = createoptions->lookup_int(ti990_createopts_sectorsize); - - totsecs = geometry.cylinders * geometry.heads * geometry.sectors_per_track; - - /* write header */ - set_UINT32BE(& header.cylinders, geometry.cylinders); - set_UINT32BE(& header.heads, geometry.heads); - set_UINT32BE(& header.sectors_per_track, geometry.sectors_per_track); - set_UINT32BE(& header.bytes_per_sector, geometry.bytes_per_sector); - - reply = stream->write(&header, sizeof(header)); - if (reply != sizeof(header)) - { - return IMGTOOLERR_WRITEERROR; - } - - - /* initialize sector 0 */ - /* mark disk as uninitialized */ - set_UINT16BE(& sec0.sta, 2); - - - /* write sector 0 */ - if (write_sector_logical(*stream, 0, & geometry, &sec0)) - return IMGTOOLERR_WRITEERROR; - - - /* now clear every other sector, including catalog */ - memset(empty_sec, 0, geometry.bytes_per_sector); - - for (i=1; i -#include -#include -#include - -/* - -sector format - -| GAP1 | IDAM | GAP2 | DATA | CHECKSUM | ... - -GAP1 = 80 80 80 80 80 00 6 -IDAM = FE E7 18 C3 Track# Sector# Checksum-8 of prev. 2 bytes 7 -GAP2 = 80 80 80 80 80 80 00 C3 18 E7 FE 11 -DATA = 126 bytes actual data 126 - = nextTrack# nextSector# 2 -CHECKSUM = Checksum-16 of the previous 128 bytes 2 - --- - 154 bytes - -sectors 0 to 14 are used for the disk directory. sector 15 is used -as track map, with one bit for each sector used. - -*/ - -#define DATA_SIZE (126) -#define SECTOR_SIZE (0x9b) -#define MAX_DIRENTS (15*8) - -/* vzdos directry entry */ -struct vzdos_dirent -{ - char ftype; - char delimitor; - char fname[8]; - uint8_t start_track; - uint8_t start_sector; - uint16_t start_address; - uint16_t end_address; - - vzdos_dirent() - { - ftype = delimitor = '\0'; - fname[0] = '\0'; - start_track = start_sector = 0; - start_address = end_address = 0; - } -}; - -struct vz_iterator -{ - int index; - int eof; -}; - -static const uint8_t sector_order[] = -{ - 0, 3, 6, 9, 12, 15, 2, 5, 8, 11, 14, 1, 4, 7, 10, 13 -}; - -/********************************************************************* - Internal functions -*********************************************************************/ - -/* get length of filename without trailing spaces */ -static int vzdos_get_fname_len(const char *fname) -{ - int len; - - for (len = 7; len > 0; len--) - if (fname[len] != 0x20) - break; - - 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) -{ - imgtoolerr_t ret; - uint8_t buffer[25]; /* enough to read the sector header */ - - ret = (imgtoolerr_t)floppy_read_sector(imgtool_floppy(img), 0, track, sector_order[sector], 0, &buffer, sizeof(buffer)); - if (ret) return ret; - - /* search for start of data */ - if (memcmp(buffer + 19, "\xC3\x18\xE7\xFE", 4) == 0) - *start = 23; - else if (memcmp(buffer + 20, "\xC3\x18\xE7\xFE", 4) == 0) - *start = 24; - else if (memcmp(buffer + 21, "\xC3\x18\xE7\xFE", 4) == 0) - *start = 25; - else - return IMGTOOLERR_CORRUPTIMAGE; - - return IMGTOOLERR_SUCCESS; -} - -/* return the actual data of a sector */ -static imgtoolerr_t vzdos_read_sector_data(imgtool::image &img, int track, int sector, uint8_t *data) -{ - int ret, data_start; - uint8_t buffer[DATA_SIZE + 4]; /* data + checksum */ - - ret = vzdos_get_data_start(img, track, sector, &data_start); - if (ret) return (imgtoolerr_t)ret; - - ret = floppy_read_sector(imgtool_floppy(img), 0, track, sector_order[sector], data_start, &buffer, sizeof(buffer)); - if (ret) return (imgtoolerr_t)ret; - - /* verify sector checksums */ - if (pick_integer_le(buffer, DATA_SIZE + 2, 2) != chksum16(buffer, DATA_SIZE + 2)) - return IMGTOOLERR_CORRUPTFILE; - - memcpy(data, &buffer, DATA_SIZE + 2); - - return IMGTOOLERR_SUCCESS; -} - -/* write data to sector */ -static imgtoolerr_t vzdos_write_sector_data(imgtool::image &img, int track, int sector, uint8_t *data) -{ - int ret, data_start; - uint8_t buffer[DATA_SIZE + 4]; /* data + checksum */ - - ret = vzdos_get_data_start(img, track, sector, &data_start); - 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)); - - 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; - - return IMGTOOLERR_SUCCESS; -} - -/* write formatted empty sector */ -static imgtoolerr_t vzdos_clear_sector(imgtool::image &img, int track, int sector) -{ - uint8_t data[DATA_SIZE + 2]; - - memset(data, 0x00, sizeof(data)); - - return vzdos_write_sector_data(img, track, sector, data); -} - -/* 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; - - 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); - - if (ent->ftype == 0x00) - return IMGTOOLERR_FILENOTFOUND; - - /* check values */ - if (ent->start_track > 39) - return IMGTOOLERR_CORRUPTFILE; - - if (ent->start_sector > 15) - return IMGTOOLERR_CORRUPTFILE; - - return IMGTOOLERR_SUCCESS; -} - -/* save a directory entry to disk */ -static imgtoolerr_t vzdos_set_dirent(imgtool::image &img, int index, vzdos_dirent ent) -{ - int ret, entry; - uint8_t buffer[DATA_SIZE + 2]; - - /* read current sector with entries */ - ret = vzdos_read_sector_data(img, 0, (int) index / 8, buffer); - if (ret) return (imgtoolerr_t)ret; - - 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); - - /* save new sector */ - ret = vzdos_write_sector_data(img, 0, (int) index / 8, buffer); - if (ret) return (imgtoolerr_t)ret; - - return IMGTOOLERR_SUCCESS; -} - -/* 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; -} - -/* 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]; - - /* check for invalid filenames */ - if (strlen(fname) > 8) - return IMGTOOLERR_BADFILENAME; - - /* TODO: check for invalid characters */ - - *entry = -1; - - for (i = 0; i < MAX_DIRENTS; i++) { - ret = vzdos_get_dirent(image, i, &ent); - if (ret) return (imgtoolerr_t)ret; - - len = vzdos_get_fname_len(ent.fname) + 1; - - if (strlen(fname) != len) - continue; - - memset(filename, 0x00, sizeof(filename)); - memcpy(filename, ent.fname, len); - - if (!core_stricmp(fname, filename)) { - *entry = i; - break; - } - - } - - if (*entry == -1) - return IMGTOOLERR_FILENOTFOUND; - - return IMGTOOLERR_SUCCESS; -} - -/* return a directory entry for a filename */ -static imgtoolerr_t vzdos_get_dirent_fname(imgtool::image &img, const char *fname, vzdos_dirent *ent) -{ - int ret, index; - - ret = vzdos_searchentry(img, fname, &index); - if (ret) return (imgtoolerr_t)ret; - - ret = vzdos_get_dirent(img, index, ent); - if (ret) return (imgtoolerr_t)ret; - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t vzdos_toggle_trackmap(imgtool::image &img, int track, int sector, int clear) -{ - int ret, value, bit; - uint8_t buffer[DATA_SIZE + 2]; - - /* get trackmap from image */ - ret = vzdos_read_sector_data(img, 0, 15, buffer); - if (ret) return (imgtoolerr_t)ret; - - value = (int) (floor(((double)track * 16 + sector) / 8) - 1); - bit = 0x01 << ((track * 16 + sector) % 8); - - if (clear) - buffer[value-1] &= ~bit; - else - buffer[value-1] |= bit; - - ret = vzdos_write_sector_data(img, 0, 15, buffer); - if (ret) return (imgtoolerr_t)ret; - - return IMGTOOLERR_SUCCESS; -} - -/* clear a trackmap entry */ -static imgtoolerr_t vzdos_clear_trackmap(imgtool::image &img, int track, int sector) -{ - return vzdos_toggle_trackmap(img, track, sector, 1); -} - -/* enable a trackmap entry */ -static imgtoolerr_t vzdos_set_trackmap(imgtool::image &img, int track, int sector) -{ - return vzdos_toggle_trackmap(img, track, sector, 0); -} - -/* return the status of a trackmap entry */ -static imgtoolerr_t vzdos_get_trackmap(imgtool::image &img, int track, int sector, int *used) -{ - int ret, value, bit; - uint8_t buffer[DATA_SIZE + 2]; - - /* get trackmap from image */ - ret = vzdos_read_sector_data(img, 0, 15, buffer); - if (ret) return (imgtoolerr_t)ret; - - value = (int) (floor(((double)track * 16 + sector) / 8) - 1); - bit = 0x01 << ((track * 16 + sector) % 8); - - if (buffer[value-1] & bit) - *used = 1; - else - *used = 0; - - return IMGTOOLERR_SUCCESS; -} - -/* return the next free sector */ -static imgtoolerr_t vzdos_free_trackmap(imgtool::image &img, int *track, int *sector) -{ - int ret, used = 0; - - for (*track = 1; *track < 40; (*track)++) { - for (*sector = 0; *sector < 16; (*sector)++) { - ret = vzdos_get_trackmap(img, *track, *sector, &used); - if (ret) return (imgtoolerr_t)ret; - if (!used) return IMGTOOLERR_SUCCESS; - } - } - - return IMGTOOLERR_NOSPACE; -} - -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] = { - 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0xFE, 0xE7, - 0x18, 0xC3, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x00, 0xC3, 0x18, 0xE7, 0xFE - }; - - memset(sector_data, 0x00, sizeof(sector_data)); - 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; - - return IMGTOOLERR_SUCCESS; -} - -/********************************************************************* - Imgtool module code -*********************************************************************/ - -static imgtoolerr_t vzdos_diskimage_beginenum(imgtool::directory &enumeration, const char *path) -{ - vz_iterator *iter; - - iter = (vz_iterator *) enumeration.extra_bytes(); - if (!iter) return IMGTOOLERR_OUTOFMEMORY; - - iter->index = 1; - iter->eof = 0; - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t vzdos_diskimage_nextenum(imgtool::directory &enumeration, imgtool_dirent &ent) -{ - vz_iterator *iter = (vz_iterator *) enumeration.extra_bytes(); - - if (iter->eof == 1 || iter->index > MAX_DIRENTS) { - ent.eof = 1; - - } else { - const char *type; - int ret, len; - vzdos_dirent dirent; - - ret = vzdos_get_dirent(enumeration.image(), iter->index - 1, &dirent); - - if (ret == IMGTOOLERR_FILENOTFOUND) - { - iter->eof = 1; - ent.eof = 1; - return IMGTOOLERR_SUCCESS; - } - - if (ret == IMGTOOLERR_CORRUPTFILE) - ent.corrupt = 1; - - /* kill trailing spaces */ - for (len = 7; len > 0; len--) { - if (dirent.fname[len] != 0x20) { - break; - } - } - - memcpy(ent.filename, &dirent.fname, len + 1); - ent.filesize = dirent.end_address - dirent.start_address; - - switch (dirent.ftype) - { - case 0x01: type = "Deleted"; break; - case 'T': type = "Basic"; break; - case 'B': type = "Binary"; break; - case 'D': type = "Data"; break; - case 'F': type = "Quickwrite"; break; - case 'A': type = "Assembler"; break; - case 'S': type = "Diskops"; break; - case 'W': type = "Wordpro"; break; - default: type = "Unknown"; - } - - snprintf(ent.attr, std::size(ent.attr), "%s", type); - - iter->index++; - } - - return IMGTOOLERR_SUCCESS; -} - -/* TRK 0 sector 15 is used to hold the track map of the disk with one bit - corresponding to a sector used. */ -static imgtoolerr_t vzdos_diskimage_freespace(imgtool::partition &partition, uint64_t *size) -{ - imgtoolerr_t ret; - int i; - imgtool::image &image(partition.image()); - uint8_t c, v, buffer[DATA_SIZE + 2]; - *size = 0; - - ret = vzdos_read_sector_data(image, 0, 15, buffer); - if (ret) return ret; - - for (i = 0; i < DATA_SIZE; i++) { - v = buffer[i]; - for (c = 0; v; c++) { - v &= v - 1; - } - *size += c * DATA_SIZE; - } - *size = (DATA_SIZE * 16 * 39) - *size; - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t vzdos_diskimage_readfile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &destf) -{ - imgtoolerr_t ret; - imgtool::image &image(partition.image()); - int filesize, track, sector; - vzdos_dirent ent; - uint8_t buffer[DATA_SIZE + 2]; - - ret = vzdos_get_dirent_fname(image, filename, &ent); - if (ret) return ret; - - filesize = ent.end_address - ent.start_address; - track = ent.start_track; - sector = ent.start_sector; - - while (filesize > 0) { - int towrite; - - ret = vzdos_read_sector_data(image, track, sector, buffer); - 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))) - 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 0 is invalid */ - if ((track == 0) && (filesize > DATA_SIZE)) - return IMGTOOLERR_CORRUPTIMAGE; - - /* write either DATA_SIZE or the remaining bytes */ - towrite = filesize > DATA_SIZE ? DATA_SIZE : filesize; - - if (destf.write(buffer, towrite) != towrite) - return IMGTOOLERR_WRITEERROR; - - filesize -= DATA_SIZE; - } - - return IMGTOOLERR_SUCCESS; -} - -/* deletes directory entry, clears trackmap entries and sectors */ -static imgtoolerr_t vzdos_diskimage_deletefile(imgtool::partition &partition, const char *fname) -{ - imgtoolerr_t ret; - imgtool::image &img(partition.image()); - int index, filesize, track, sector, next_track, next_sector; - vzdos_dirent entry, next_entry; - uint8_t buffer[DATA_SIZE + 2]; - - ret = vzdos_get_dirent_fname(img, fname, &entry); - if (ret) return ret; - - ret = (imgtoolerr_t)floppy_read_sector(imgtool_floppy(img), 0, entry.start_track, sector_order[entry.start_sector], 24, &buffer, DATA_SIZE + 2); - if (ret) return ret; - - filesize = entry.end_address - entry.start_address; - track = entry.start_track; - sector = entry.start_sector; - - /* delete directory entry */ - ret = vzdos_searchentry(img, fname, &index); - if (ret) return ret; - - ret = vzdos_get_dirent(img, index + 1, &next_entry); - - if (ret == IMGTOOLERR_FILENOTFOUND) { - /* we are the last directory entry, just delete it */ - ret = vzdos_clear_dirent(img, index); - if (ret) return ret; - - } else if (ret) { - /* an error occurred */ - return ret; - - } else { - ret = vzdos_set_dirent(img, index++, next_entry); - if (ret) return ret; - - while ((ret = vzdos_get_dirent(img, index + 1, &next_entry)) != IMGTOOLERR_FILENOTFOUND) { - if (ret) return ret; - ret = vzdos_set_dirent(img, index++, next_entry); - if (ret) return ret; - } - - ret = vzdos_clear_dirent(img, index); - if (ret) return ret; - - } - - /* clear sectors and trackmap entries */ - while (filesize > 0) { - filesize -= DATA_SIZE; - - /* clear trackmap entry */ - ret = vzdos_clear_trackmap(img, track, sector); - 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); - - /* overwrite sector with default values */ - ret = vzdos_clear_sector(img, track, sector); - if (ret) return ret; - - /* read next sector */ - track = next_track; - sector = next_sector; - - if (filesize > 0) { - ret = (imgtoolerr_t)floppy_read_sector(imgtool_floppy(img), 0, track, sector_order[sector], 24, &buffer, DATA_SIZE + 2); - if (ret) return ret; - } - - } - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t vzdos_writefile(imgtool::partition &partition, int offset, imgtool::stream &sourcef, vzdos_dirent *entry) -{ - imgtoolerr_t ret; - imgtool::image &img(partition.image()); - int index, track, sector, toread, next_track, next_sector; - vzdos_dirent temp_entry; - uint64_t filesize = 0, freespace = 0; - uint8_t buffer[DATA_SIZE + 2]; - char filename[9]; - - /* is the image writeable? */ - if (floppy_is_read_only(imgtool_floppy(img))) - return IMGTOOLERR_READONLY; - - /* check for already existing filename -> overwrite */ - strcpy(filename, entry->fname); - filename[vzdos_get_fname_len(entry->fname) + 1] = 0x00; - ret = vzdos_get_dirent_fname(img, filename, &temp_entry); - if (!ret) { - /* file already exists, delete it */ - ret = vzdos_diskimage_deletefile(partition, filename); - if (ret) return ret; - } else if (ret != IMGTOOLERR_FILENOTFOUND) { - /* another error occurred, return it */ - return ret; - } - - ret = (imgtoolerr_t) sourcef.seek(offset, SEEK_SET); - if (ret) return ret; - - /* check if there is enough space */ - filesize = sourcef.size() - offset; - - ret = vzdos_diskimage_freespace(partition, &freespace); - if (ret) return ret; - - if (filesize > freespace) - return IMGTOOLERR_NOSPACE; - - /* get next free track and sector */ - ret = vzdos_free_trackmap(img, &track, §or); - if (ret) return ret; - - entry->end_address = entry->start_address + (unsigned int) filesize; - entry->start_track = track; - entry->start_sector = sector; - - /* search for next free directory entry */ - for (index = 0; index < MAX_DIRENTS; index++) { - ret = vzdos_get_dirent(img, index, &temp_entry); - if (ret == IMGTOOLERR_FILENOTFOUND) - break; - else if (ret) - return (ret); - } - - /* write directory entry to disk */ - ret = vzdos_set_dirent(img, index, *entry); - if (ret) return ret; - - next_track = 0; - next_sector = 0; - - /* write data to disk */ - while (filesize > 0) { - toread = filesize > DATA_SIZE ? DATA_SIZE : filesize; - sourcef.read(buffer, toread); - - filesize -= toread; - - /* mark sector as used */ - ret = vzdos_set_trackmap(img, track, sector); - if (ret) return ret; - - /* get track and sector for next sector */ - if (filesize > 0) { - ret = vzdos_free_trackmap(img, &next_track, &next_sector); - if (ret) return ret; - } else { - next_track = 0; - next_sector = 0; - } - buffer[DATA_SIZE] = next_track; - buffer[DATA_SIZE + 1] = next_sector; - - /* write sector to disk */ - ret = vzdos_write_sector_data(img, track, sector, buffer); - if (ret) return ret; - - track = next_track; - sector = next_sector; - } - - return IMGTOOLERR_SUCCESS; - -} - -/* 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 */ - if (strlen(filename) > 8 || strlen(filename) < 1) - return IMGTOOLERR_BADFILENAME; - - /* prepare directory entry */ - ftype = opts->lookup_int('T'); - - switch (ftype) { - case 0: - entry.ftype = 'T'; - entry.start_address = 31465; - break; - case 1: - entry.ftype = 'B'; - entry.start_address = 31465; /* ??? */ - break; - case 2: - entry.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)); - - /* write file to disk */ - ret = vzdos_writefile(partition, 0, sourcef, &entry); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - -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()); - vzdos_dirent entry; - - if (fname) { - ret = vzdos_get_dirent_fname(image, fname, &entry); - if (ret) return ret; - - switch (entry.ftype) { - case 'B': - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = filter_vzsnapshot_getinfo; - suggestions[0].description = "VZ Snapshot"; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = NULL; - suggestions[1].description = "Raw"; - break; - case 'T': - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = filter_vzsnapshot_getinfo; - suggestions[0].description = "VZ Snapshot"; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = NULL; - suggestions[1].description = "Raw"; - suggestions[2].viability = 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].description = "Raw"; - } - - } else { - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; - suggestions[0].description = "Raw"; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = filter_vzsnapshot_getinfo; - suggestions[1].description = "VZ Snapshot"; - } - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t vzdos_diskimage_create(imgtool::image &img, imgtool::stream::ptr &&dummy, util::option_resolution *opts) -{ - imgtoolerr_t ret; - int track, sector; - - for (track = 0; track < 40; track++) { - for (sector = 0; sector < 16; sector++) { - ret = vzdos_write_formatted_sector(img, track, sector); - if (ret) return ret; - } - } - - return IMGTOOLERR_SUCCESS; -} - -/********************************************************************* - Imgtool vz filter code -*********************************************************************/ - -static imgtoolerr_t vzsnapshot_readfile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &destf) -{ - imgtoolerr_t ret; - imgtool::image &image(partition.image()); - vzdos_dirent entry; - uint8_t header[24]; - - /* get directory entry from disk */ - ret = vzdos_get_dirent_fname(image, filename, &entry); - if (ret) return ret; - - /* prepare header */ - header[0] = 'V'; - header[1] = 'Z'; - header[2] = 'F'; - - switch (entry.ftype) { - case 'B': - header[3] = '1'; - header[21] = 0xF1; - break; - case 'T': - header[3] = '0'; - header[21] = 0xF0; - break; - default: - memset(header, 0x00, 4); - header[21] = 0x00; - } - - 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); - - /* write header to file */ - destf.write(header, sizeof(header)); - - /* write data to file */ - ret = vzdos_diskimage_readfile(partition, filename, "", destf); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t vzsnapshot_writefile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &sourcef, util::option_resolution *opts) -{ - imgtoolerr_t ret; - int fnameopt; - vzdos_dirent entry; - uint8_t header[24]; - - /* get header infos from file */ - 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); - - /* filename from header or directly? */ - fnameopt = opts->lookup_int('F'); - - if (fnameopt == 0) { - memcpy(&entry.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); - } - - /* write file to disk */ - ret = vzdos_writefile(partition, 24, sourcef, &entry); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - -void filter_vzsnapshot_getinfo(uint32_t state, union filterinfo *info) -{ - switch(state) - { - case FILTINFO_STR_NAME: info->s = "vzsnapshot"; break; - case FILTINFO_STR_HUMANNAME: info->s = "VZ Snapshot"; break; - case FILTINFO_STR_EXTENSION: info->s = "vz"; break; - case FILTINFO_PTR_READFILE: info->read_file = vzsnapshot_readfile; break; - case FILTINFO_PTR_WRITEFILE: info->write_file = vzsnapshot_writefile; break; - } -} - -/********************************************************************* - Imgtool module declaration -*********************************************************************/ - -OPTION_GUIDE_START(vzdos_writefile_optionguide) - OPTION_ENUM_START( 'T', "ftype", "File type" ) - OPTION_ENUM( 0, "basic", "Basic" ) - OPTION_ENUM( 1, "binary", "Binary" ) - OPTION_ENUM( 2, "data", "Data" ) - OPTION_ENUM_END - OPTION_ENUM_START( 'F', "fname", "Filename" ) - OPTION_ENUM( 0, "intern", "Filename from VZ-Header" ) - OPTION_ENUM( 1, "extern", "Actual filename" ) - OPTION_ENUM_END -OPTION_GUIDE_END - -/* -T Basic Editor File -B Binary File -D Sequential Access Program Data File -F Quickwrite Document -A Russell Harrison's Edit Ass. File -S Dave Mitchell/Mark Hardwood Edit Ass. File Start Addr A280H -S Quickwrite/Diskops System File/Label Except Above -W Edit Ass. with Diskops File Start Addr A813H -W E & F Word Pro with Patch 3.3 File End Addr D000H -W Russell Harrison Word Pro File Except above two -*/ - -void vzdos_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(vz_iterator); break; - - /* --- the following bits of info are returned as NULL-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; - - /* --- 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_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; - case IMGTOOLINFO_PTR_READ_FILE: info->read_file = vzdos_diskimage_readfile; break; - case IMGTOOLINFO_PTR_WRITE_FILE: info->write_file = vzdos_diskimage_writefile; break; - case IMGTOOLINFO_PTR_DELETE_FILE: info->delete_file = vzdos_diskimage_deletefile; break; - case IMGTOOLINFO_PTR_FLOPPY_CREATE: info->create = vzdos_diskimage_create; break; - case IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE: info->writefile_optguide = &vzdos_writefile_optionguide; break; - case IMGTOOLINFO_PTR_SUGGEST_TRANSFER: info->suggest_transfer = vzdos_diskimage_suggesttransfer; break; - case IMGTOOLINFO_PTR_FLOPPY_FORMAT: info->p = (void *) floppyoptions_vz; break; - } -} diff --git a/src/tools/imgtool/stream.cpp b/src/tools/imgtool/stream.cpp deleted file mode 100644 index 014d573..0000000 --- a/src/tools/imgtool/stream.cpp +++ /dev/null @@ -1,694 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/*************************************************************************** - - stream.cpp - - Code for implementing Imgtool streams - -***************************************************************************/ - -#include "stream.h" - -#include "imgtool.h" - -#include "corefile.h" -#include "ioprocs.h" -#include "unzip.h" - -#include -#include -#include - -#include // for crc32 - - -namespace imgtool { - -namespace { - -class stream_read_wrapper : public virtual util::random_read -{ -public: - stream_read_wrapper(stream::ptr &&stream, std::uint8_t filler) noexcept - : m_stream(stream.release()) - , m_filler(filler) - , m_close(true) - { - assert(m_stream); - } - - stream_read_wrapper(stream &stream, std::uint8_t filler) noexcept - : m_stream(&stream) - , m_filler(filler) - , m_close(false) - { - } - - virtual ~stream_read_wrapper() - { - if (m_close) - delete m_stream; - } - - virtual std::error_condition seek(std::int64_t offset, int whence) noexcept override - { - m_stream->seek(offset, whence); - return std::error_condition(); - } - - virtual std::error_condition tell(std::uint64_t &result) noexcept override - { - result = m_stream->tell(); - return std::error_condition(); - } - - virtual std::error_condition length(std::uint64_t &result) noexcept override - { - result = m_stream->size(); - return std::error_condition(); - } - - virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override - { - actual = m_stream->read(buffer, length); - if (actual < length) - std::memset(reinterpret_cast(buffer) + actual, m_filler, length - actual); - return std::error_condition(); - } - - virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override - { - std::uint64_t const pos = m_stream->tell(); - m_stream->seek(offset, SEEK_SET); - actual = m_stream->read(buffer, length); - m_stream->seek(pos, SEEK_SET); - if (actual < length) - std::memset(reinterpret_cast(buffer) + actual, m_filler, length - actual); - return std::error_condition(); - } - -protected: - stream *const m_stream; - std::uint8_t m_filler; - bool const m_close; -}; - - -class stream_read_write_wrapper : public stream_read_wrapper, public util::random_read_write -{ -public: - using stream_read_wrapper::stream_read_wrapper; - - virtual std::error_condition finalize() noexcept override - { - return std::error_condition(); - } - - virtual std::error_condition flush() noexcept override - { - return std::error_condition(); - } - - virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override - { - std::uint64_t const pos = m_stream->tell(); - std::uint64_t size = m_stream->size(); - if (size < pos) - { - m_stream->seek(size, SEEK_SET); - size += m_stream->fill(m_filler, pos - size); - } - actual = (size >= pos) ? m_stream->write(buffer, length) : 0U; - return (actual == length) ? std::error_condition() : std::errc::io_error; - } - - virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override - { - std::uint64_t const pos = m_stream->tell(); - std::uint64_t size = m_stream->size(); - if (offset > size) - { - m_stream->seek(size, SEEK_SET); - size += m_stream->fill(m_filler, offset - size); - } - else - { - m_stream->seek(offset, SEEK_SET); - } - actual = (size >= offset) ? m_stream->write(buffer, length) : 0U; - m_stream->seek(pos, SEEK_SET); - return (actual == length) ? std::error_condition() : std::errc::io_error; - } -}; - -} // anonymous namespace - - -util::random_read::ptr stream_read(stream::ptr &&s, std::uint8_t filler) noexcept -{ - util::random_read::ptr result; - if (s) - result.reset(new (std::nothrow) stream_read_wrapper(std::move(s), filler)); - return result; -} - -util::random_read::ptr stream_read(stream &s, std::uint8_t filler) noexcept -{ - util::random_read::ptr result(new (std::nothrow) stream_read_wrapper(s, filler)); - return result; -} - -util::random_read_write::ptr stream_read_write(stream::ptr &&s, std::uint8_t filler) noexcept -{ - util::random_read_write::ptr result; - if (s) - result.reset(new (std::nothrow) stream_read_write_wrapper(std::move(s), filler)); - return result; -} - -util::random_read_write::ptr stream_read_write(stream &s, std::uint8_t filler) noexcept -{ - util::random_read_write::ptr result(new (std::nothrow) stream_read_write_wrapper(s, filler)); - return result; -} - - - -//------------------------------------------------- -// ctor -//------------------------------------------------- - -stream::stream(bool wp) - : imgtype(IMG_FILE) - , write_protect(wp) - , position(0) - , filesize(0) - , file() - , buffer(nullptr) -{ -} - - -//------------------------------------------------- -// ctor -//------------------------------------------------- - -stream::stream(bool wp, util::core_file::ptr &&f) - : imgtype(IMG_FILE) - , write_protect(wp) - , position(0) - , filesize(0) - , file(std::move(f)) - , buffer(nullptr) -{ - file->length(filesize); // FIXME: check error return -} - - -//------------------------------------------------- -// ctor -//------------------------------------------------- - -stream::stream(bool wp, std::size_t size) - : imgtype(IMG_MEM) - , write_protect(wp) - , position(0) - , filesize(size) - , file() - , buffer(reinterpret_cast(malloc(size))) -{ -} - - -//------------------------------------------------- -// ctor -//------------------------------------------------- - -stream::stream(bool wp, std::size_t size, void *buf) - : imgtype(IMG_MEM) - , write_protect(wp) - , position(0) - , filesize(size) - , file() - , buffer(reinterpret_cast(buf)) -{ -} - - -//------------------------------------------------- -// dtor -//------------------------------------------------- - -stream::~stream() -{ - if (buffer) - free(buffer); -} - - -//------------------------------------------------- -// open_zip -//------------------------------------------------- - -stream::ptr stream::open_zip(const std::string &zipname, const char *subname, int read_or_write) -{ - if (read_or_write) - return stream::ptr(); - - /* check to see if the file exists */ - FILE *f = fopen(zipname.c_str(), "r"); - if (!f) - return stream::ptr(); - fclose(f); - - 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 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 stream::ptr(); - - imgfile->filesize = z->current_uncompressed_length(); - imgfile->buffer = reinterpret_cast(malloc(z->current_uncompressed_length())); - if (!imgfile->buffer) - return stream::ptr(); - - if (z->decompress(imgfile->buffer, z->current_uncompressed_length())) - return stream::ptr(); - - return imgfile; -} - - - -//------------------------------------------------- -// open -//------------------------------------------------- - -stream::ptr stream::open(const std::string &filename, int read_or_write) -{ - static const uint32_t write_modes[] = - { - OPEN_FLAG_READ, - OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, - OPEN_FLAG_READ | OPEN_FLAG_WRITE, - OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE - }; - stream::ptr s; - char c; - - // maybe we are just a 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) - { - if (!read_or_write) - { - int const len = filename.size(); - - // can't open the file; try opening ZIP files with other names - std::vector buf(len + 1); - strcpy(&buf[0], filename.c_str()); - - for (int i = len-1; !s && (i >= 0); i--) - { - if ((buf[i] == '\\') || (buf[i] == '/')) - { - c = buf[i]; - buf[i] = '\0'; - s = open_zip(&buf[0], &buf[i + 1], read_or_write); - buf[i] = c; - } - } - - if (s) - return s; - } - - // ah well, it was worth a shot - return stream::ptr(); - } - - stream::ptr imgfile(new stream(read_or_write ? false : true, std::move(f))); - - // normal file - return imgfile; -} - - -//------------------------------------------------- -// open_write_stream -//------------------------------------------------- - -stream::ptr stream::open_write_stream(int size) -{ - stream::ptr imgfile(new stream(false, size)); - if (!imgfile->buffer) - return stream::ptr(); - - return imgfile; -} - - -//------------------------------------------------- -// open_mem -//------------------------------------------------- - -stream::ptr stream::open_mem(void *buf, size_t sz) -{ - stream::ptr imgfile(new stream(false, sz, buf)); - - return imgfile; -} - - -//------------------------------------------------- -// core_file -//------------------------------------------------- - -util::core_file *stream::core_file() -{ - return (imgtype == IMG_FILE) ? file.get() : nullptr; -} - - -//------------------------------------------------- -// read -//------------------------------------------------- - -uint32_t stream::read(void *buf, uint32_t sz) -{ - size_t result = 0; - - switch(imgtype) - { - case IMG_FILE: - if (!file->seek(position, SEEK_SET)) - file->read(buf, sz, result); // FIXME: check error return - break; - - case IMG_MEM: - // do we have to limit sz? - if (sz > (filesize - position)) - sz = uint32_t(filesize - position); - - memcpy(buf, buffer + position, sz); - result = sz; - break; - - default: - assert(0); - break; - } - position += result; - return result; -} - - -//------------------------------------------------- -// write -//------------------------------------------------- - -uint32_t stream::write(const void *buf, uint32_t sz) -{ - size_t result = 0; - - switch(imgtype) - { - case IMG_MEM: - if (!write_protect) - { - // 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 - void *const new_buffer = realloc(buffer, size_t(end)); - if (new_buffer) - { - buffer = reinterpret_cast(new_buffer); - filesize = end; - } - } - - // do we have to limit sz? - if (sz > (filesize - position)) - sz = uint32_t(filesize - position); - - memcpy(buffer + position, buf, sz); - result = sz; - } - break; - - case IMG_FILE: - if (!file->seek(position, SEEK_SET)) - file->write(buf, sz, result); // FIXME: check error return - break; - - default: - assert(0); - break; - } - - // advance the file pointer - position += result; - - // did we grow the file - if (position > filesize) - filesize = position; - return result; -} - - -//------------------------------------------------- -// size -//------------------------------------------------- - -uint64_t stream::size() const -{ - return filesize; -} - - -//------------------------------------------------- -// getptr -//------------------------------------------------- - -void *stream::getptr() -{ - void *ptr; - - switch(imgtype) - { - case IMG_MEM: - ptr = buffer; - break; - - default: - ptr = nullptr; - break; - } - return ptr; -} - - -//------------------------------------------------- -// seek -//------------------------------------------------- - -int stream::seek(int64_t pos, int where) -{ - switch(where) - { - case SEEK_CUR: - pos += position; - break; - case SEEK_END: - pos += size(); - break; - } - - if (pos < 0) - position = 0; - else - position = std::min(size(), uint64_t(pos)); - - if (position < pos) - fill('\0', pos - position); - - return 0; -} - - -//------------------------------------------------- -// tell -//------------------------------------------------- - -uint64_t stream::tell() -{ - return position; -} - - -//------------------------------------------------- -// transfer -//------------------------------------------------- - -uint64_t stream::transfer(stream &dest, stream &source, uint64_t sz) -{ - uint64_t result = 0; - uint64_t readsz; - char buf[1024]; - - while(sz && (readsz = source.read(buf, std::min(sz, uint64_t(sizeof(buf)))))) - { - dest.write(buf, readsz); - sz -= readsz; - result += readsz; - } - return result; -} - - -//------------------------------------------------- -// transfer_all -//------------------------------------------------- - -uint64_t stream::transfer_all(stream &dest, stream &source) -{ - return transfer(dest, source, source.size()); -} - - -//------------------------------------------------- -// crc -//------------------------------------------------- - -int 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 stream::file_crc(const char *fname, unsigned long *result) -{ - int err; - stream::ptr f; - - f = stream::open(fname, OSD_FOPEN_READ); - if (!f) - return IMGTOOLERR_FILENOTFOUND; - - err = f->crc(result); - return err; -} - - -//------------------------------------------------- -// fill -//------------------------------------------------- - -uint64_t stream::fill(unsigned char b, uint64_t sz) -{ - uint64_t outsz; - char buf[1024]; - - outsz = 0; - memset(buf, b, (std::min)(sz, sizeof(buf))); - - while (sz) - { - outsz += write(buf, (std::min)(sz, sizeof(buf))); - sz -= (std::min)(sz, sizeof(buf)); - } - return outsz; -} - - -//------------------------------------------------- -// is_read_only -//------------------------------------------------- - -bool stream::is_read_only() -{ - return write_protect; -} - - -//------------------------------------------------- -// putc -//------------------------------------------------- - -uint32_t stream::putc(char c) -{ - return write(&c, 1); -} - - -//------------------------------------------------- -// puts -//------------------------------------------------- - -uint32_t stream::puts(const char *s) -{ - return write(s, strlen(s)); -} - - -//------------------------------------------------- -// printf -//------------------------------------------------- - -uint32_t stream::printf(const char *fmt, ...) -{ - va_list va; - char buf[256]; - - va_start(va, fmt); - vsprintf(buf, fmt, va); - va_end(va); - - return puts(buf); -} - -} // namespace imgtool diff --git a/src/tools/imgtool/stream.h b/src/tools/imgtool/stream.h deleted file mode 100644 index 36872e3..0000000 --- a/src/tools/imgtool/stream.h +++ /dev/null @@ -1,95 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/*************************************************************************** - - stream.h - - Code for implementing Imgtool streams - -***************************************************************************/ -#ifndef MAME_TOOLS_IMGTOOL_STREAM_H -#define MAME_TOOLS_IMGTOOL_STREAM_H - -#pragma once - -#include "utilfwd.h" - -#include "osdcomm.h" - -#include -#include -#include - - -namespace imgtool { - -class stream -{ -public: - typedef std::unique_ptr 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; - - std::unique_ptr file; - std::uint8_t *buffer; - - // ctors - stream(bool wp); - stream(bool wp, std::unique_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); -}; - - -std::unique_ptr stream_read(stream::ptr &&s, std::uint8_t filler) noexcept; -std::unique_ptr stream_read(stream &s, std::uint8_t filler) noexcept; -std::unique_ptr stream_read_write(stream::ptr &&s, std::uint8_t filler) noexcept; -std::unique_ptr stream_read_write(stream &s, std::uint8_t filler) noexcept; - -} // namespace imgtool - -#endif // MAME_TOOLS_IMGTOOL_STREAM_H diff --git a/src/tools/jedutil.cpp b/src/tools/jedutil.cpp deleted file mode 100644 index a4ea6b5..0000000 --- a/src/tools/jedutil.cpp +++ /dev/null @@ -1,8261 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Aaron Giles -/*************************************************************************** - - jedutil.c - - JEDEC file utilities. - -**************************************************************************** - - Binary file format: - - Offset - 0 = Total number of fuses (32 bits) - 4 = Raw fuse data, packed 8 bits at a time, LSB to MSB - -**************************************************************************** - - Known types: - - 20-pin devices: - PAL10H8 = QP20 QF0320 - PAL12H6 = QP20 QF0320 - PAL14H4 = QP20 QF0448 - PAL16H2 = QP20 QF0512 - PAL16C1 = QP20 QF0512 - PAL10L8 = QP20 QF0320 - PAL12L6 = QP20 QF0320 - PAL14L4 = QP20 QF0448 - PAL16L2 = QP20 QF0512 - - PAL10P8 = QP20 QF0328 - PAL12P6 = QP20 QF0390 - PAL14P4 = QP20 QF0452 - PAL16P2 = QP20 QF0514 - PAL16P8 = QP20 QF2056 - PAL16RP4 = QP20 QF2056 - PAL16RP6 = QP20 QF2056 - PAL16RP8 = QP20 QF2056 - - 15S8 = QP20 QF0448 - - CK2605 = QP20 QF1106 - - PLS153 = QP20 QF1842 - - PAL16L8 = QP20 QF2048 - - PAL16R4 = QP20 QF2048 - PAL16R6 = QP20 QF2048 - PAL16R8 = QP20 QF2048 - PAL16RA8 = QP20 QF2056? - - 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 - EPL16P2 = QP20 - EPL16P8 = QP20 QF2072 - EPL16RP8 = QP20 - EPL16RP6 = QP20 - EPL16RP4 = QP20 - - PAL16A4 = QP20 - PAL16X4 = QP20 - - 24-pin devices: - PAL6L16 = QP24 QF0192 - PAL8L14 = QP24 QF0224 - PAL12H10 = QP24 QF0480 - PAL12L10 = QP24 QF0480 - PAL14H8 = QP24 QF0560 - PAL14L8 = QP24 QF0560 - PAL16H6 = QP24 QF0640 - PAL16L6 = QP24 QF0640 - PAL18H4 = QP24 QF0720 - PAL18L4 = QP24 QF0720 - PAL20C1 = QP24 QF0640 - PAL20L2 = QP24 QF0640 - - PAL20L8 = QP24 QF2560 - PAL20L10 = QP24 QF1600 - PAL20R4 = QP24 QF2560 - PAL20R6 = QP24 QF2560 - PAL20R8 = QP24 QF2560 - - PAL20RA10 = QP24 QF3210 - - PAL20X4 = QP24 QF1600 - PAL20X8 = QP24 QF1600 - PAL20X10 = QP24 QF1600 - - 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) - 82S100 = QP20 QF1928 (Tri-State) - PLS101 = QP20 QF1928 (Open Collector) - 82S101 = QP20 QF1928 (Open Collector) - -**************************************************************************** - - Thanks to Charles MacDonald (http://cgfm2.emuviews.com/) for providing - information on how to decode the PLS153/82S153 and CK2605 fuse map. - -***************************************************************************/ - -#include -#include -#include -#include -#include - -#include -#include - -#include "corestr.h" -#include "ioprocs.h" -#include "jedparse.h" -#include "plaparse.h" - - - -/*************************************************************************** - CONSTANTS -***************************************************************************/ - -#define NO_OUTPUT_ENABLE_FUSE_ROW 0xFFFF - -/* Output pin flags */ -#define OUTPUT_ACTIVELOW 0x00000001 -#define OUTPUT_ACTIVEHIGH 0x00000002 -#define OUTPUT_COMBINATORIAL 0x00000004 -#define OUTPUT_REGISTERED 0x00000008 -#define OUTPUT_FEEDBACK_OUTPUT 0x00000010 /* Feedback state depends on output enable */ -#define OUTPUT_FEEDBACK_COMBINATORIAL 0x00000020 /* Feedback state independent of output enable */ -#define OUTPUT_FEEDBACK_REGISTERED 0x00000040 /* Feedback state independent of output enable */ -#define OUTPUT_FEEDBACK_NONE 0x00000080 /* Feedback not available */ - -/* - Output Feedback Output - - OE -----------| - | - |-\ - IN ----------| >----|----< OUT > - |-/ | - | - FEEDBACK ------------| - - - - Output Feedback Combinatorial/Registered - - OE ----------------| - | - |-\ - IN ----------|----| >----< OUT > - | |-/ - | - FEEDBACK ----| -*/ - - - -/* Fuse state flag */ -#define LOW_FUSE_BLOWN 0x00000001 -#define HIGH_FUSE_BLOWN 0x00000002 -#define LOWHIGH_FUSE_BLOWN 0x00000004 -#define NO_FUSE_BLOWN 0x00000008 - - - -/* Symbols */ -#define AND_SYMBOL "&" -#define OR_SYMBOL "+" -#define XOR_SYMBOL ":+:" - -#define LOW_SYMBOL "/" - -#define INPUT_SYMBOL "i" -#define OUTPUT_SYMBOL "o" -#define REGISTERED_FEEDBACK_OUTPUT_SYMBOL "rfo" -#define OUTPUT_FEEDBACK_SYMBOL "of" -#define REGISTERED_FEEDBACK_SYMBOL "rf" - -#define COMBINATORIAL_ASSIGNMENT "=" -#define REGISTERED_ASSIGNMENT ":=" - - - -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ - -typedef int (*command_func_type)(int argc, char *argv[]); - -typedef struct _command_entry command_entry; -struct _command_entry -{ - const char *command; - command_func_type command_func; -}; - - - -/* Pin fuse row configuration */ -typedef struct _pin_fuse_rows pin_fuse_rows; -struct _pin_fuse_rows -{ - uint16_t pin; /* Pin number */ - uint16_t fuserowoutputenable; /* Fuse row for the output enable */ - uint16_t fuserowtermstart; /* Fuse row for the first term */ - uint16_t fuserowtermend; /* Fuse row for the last term */ -}; - - - -/* Pin fuse column configuration */ -typedef struct _pin_fuse_columns pin_fuse_columns; -struct _pin_fuse_columns -{ - uint16_t pin; /* Pin number */ - uint16_t lowfusecolumn; /* Column number for low output */ - uint16_t highfusecolumn; /* Column number for high output */ -}; - - -typedef struct _pal_data pal_data; - -typedef void (*print_product_terms_func)(const pal_data* pal, const jed_data* jed); -typedef void (*config_pins_func)(const pal_data* pal, const jed_data* jed); -typedef int (*is_product_term_enabled_func)(const pal_data* pal, const jed_data* jed, uint16_t fuserow); -typedef uint16_t (*get_pin_fuse_state_func)(const pal_data* pal, const jed_data* jed, uint16_t pin, uint16_t fuserow); - -struct _pal_data -{ - const char *name; - uint32_t numfuses; - const pin_fuse_rows *pinfuserows; - uint16_t pinfuserowscount; - const pin_fuse_columns *pinfusecolumns; - uint16_t pinfusecolumnscount; - print_product_terms_func print_product_terms; - config_pins_func config_pins; - is_product_term_enabled_func is_product_term_enabled; - get_pin_fuse_state_func get_pin_fuse_state; -}; - - - -/* Pin output configuration */ -typedef struct _pin_output_config pin_output_config; -struct _pin_output_config -{ - uint16_t pin; - uint16_t flags; -}; - - - -typedef std::vector pal_data_vector; - - - -/*************************************************************************** - FUNCTION PROTOTYPES -***************************************************************************/ - -static void print_pal10l8_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal10h8_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal12l6_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal12h6_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal14l4_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal14h4_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal16l2_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal16h2_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal16c1_product_terms(const pal_data* pal, const jed_data* jed); -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_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); -static void print_gal18v10_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal20l8_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal20l10_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal20r4_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal20r6_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal20r8_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal20ra10_product_terms(const pal_data* pal, const jed_data* jed); -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) -static void print_epl10p8_product_terms(const pal_data* pal, const jed_data* jed); -static void print_epl12p6_product_terms(const pal_data* pal, const jed_data* jed); -static void print_epl14p4_product_terms(const pal_data* pal, const jed_data* jed); -static void print_epl16p2_product_terms(const pal_data* pal, const jed_data* jed); -static void print_epl16p8_product_terms(const pal_data* pal, const jed_data* jed); -static void print_epl16rp8_product_terms(const pal_data* pal, const jed_data* jed); -static void print_epl16rp6_product_terms(const pal_data* pal, const jed_data* jed); -static void print_epl16rp4_product_terms(const pal_data* pal, const jed_data* jed); -#endif -static void print_pal10p8_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal12p6_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal14p4_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal16p2_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal16p8_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal16rp4_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal16rp6_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal16rp8_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal6l16_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal8l14_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal12h10_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal12l10_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal14h8_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal14l8_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal16h6_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal16l6_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal18h4_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal18l4_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal20c1_product_terms(const pal_data* pal, const jed_data* jed); -static void print_pal20l2_product_terms(const pal_data* pal, const jed_data* jed); -static void print_82s100_pls100_product_terms(const pal_data* pal, const jed_data* jed); - - - -static void config_pal10l8_pins(const pal_data* pal, const jed_data* jed); -static void config_pal10h8_pins(const pal_data* pal, const jed_data* jed); -static void config_pal12l6_pins(const pal_data* pal, const jed_data* jed); -static void config_pal12h6_pins(const pal_data* pal, const jed_data* jed); -static void config_pal14l4_pins(const pal_data* pal, const jed_data* jed); -static void config_pal14h4_pins(const pal_data* pal, const jed_data* jed); -static void config_pal16l2_pins(const pal_data* pal, const jed_data* jed); -static void config_pal16h2_pins(const pal_data* pal, const jed_data* jed); -static void config_pal16c1_pins(const pal_data* pal, const jed_data* jed); -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_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); -static void config_gal18v10_pins(const pal_data* pal, const jed_data* jed); -static void config_pal20l8_pins(const pal_data* pal, const jed_data* jed); -static void config_pal20l10_pins(const pal_data* pal, const jed_data* jed); -static void config_pal20r4_pins(const pal_data* pal, const jed_data* jed); -static void config_pal20r6_pins(const pal_data* pal, const jed_data* jed); -static void config_pal20r8_pins(const pal_data* pal, const jed_data* jed); -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) -static void config_epl10p8_pins(const pal_data* pal, const jed_data* jed); -static void config_epl12p6_pins(const pal_data* pal, const jed_data* jed); -static void config_epl14p4_pins(const pal_data* pal, const jed_data* jed); -static void config_epl16p2_pins(const pal_data* pal, const jed_data* jed); -static void config_epl16p8_pins(const pal_data* pal, const jed_data* jed); -static void config_epl16rp8_pins(const pal_data* pal, const jed_data* jed); -static void config_epl16rp6_pins(const pal_data* pal, const jed_data* jed); -static void config_epl16rp4_pins(const pal_data* pal, const jed_data* jed); -#endif -static void config_pal10p8_pins(const pal_data* pal, const jed_data* jed); -static void config_pal12p6_pins(const pal_data* pal, const jed_data* jed); -static void config_pal14p4_pins(const pal_data* pal, const jed_data* jed); -static void config_pal16p2_pins(const pal_data* pal, const jed_data* jed); -static void config_pal16p8_pins(const pal_data* pal, const jed_data* jed); -static void config_pal16rp4_pins(const pal_data* pal, const jed_data* jed); -static void config_pal16rp6_pins(const pal_data* pal, const jed_data* jed); -static void config_pal16rp8_pins(const pal_data* pal, const jed_data* jed); -static void config_pal6l16_pins(const pal_data* pal, const jed_data* jed); -static void config_pal8l14_pins(const pal_data* pal, const jed_data* jed); -static void config_pal12h10_pins(const pal_data* pal, const jed_data* jed); -static void config_pal12l10_pins(const pal_data* pal, const jed_data* jed); -static void config_pal14h8_pins(const pal_data* pal, const jed_data* jed); -static void config_pal14l8_pins(const pal_data* pal, const jed_data* jed); -static void config_pal16h6_pins(const pal_data* pal, const jed_data* jed); -static void config_pal16l6_pins(const pal_data* pal, const jed_data* jed); -static void config_pal18h4_pins(const pal_data* pal, const jed_data* jed); -static void config_pal18l4_pins(const pal_data* pal, const jed_data* jed); -static void config_pal20c1_pins(const pal_data* pal, const jed_data* jed); -static void config_pal20l2_pins(const pal_data* pal, const jed_data* jed); -static void config_82s100_pls100_pins(const pal_data* pal, const jed_data* jed); - - - -static int is_gal16v8_product_term_enabled(const pal_data* pal, const jed_data* jed, uint16_t fuserow); - - - -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); - - - -/*************************************************************************** - GLOBAL VARIABLES -***************************************************************************/ - -static uint8_t *dstbuf; -static size_t dstbuflen; - -static uint16_t inputpins[26]; -static uint16_t inputpinscount; - -static pin_output_config outputpins[26]; -static uint16_t outputpinscount; - -static pin_fuse_rows pal10l8pinfuserows[] = { - {12, NO_OUTPUT_ENABLE_FUSE_ROW, 280, 300}, - {13, NO_OUTPUT_ENABLE_FUSE_ROW, 240, 260}, - {14, NO_OUTPUT_ENABLE_FUSE_ROW, 200, 220}, - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 160, 180}, - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 120, 140}, - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 80, 100}, - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 40, 60}, - {19, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 20}}; - -static pin_fuse_rows pal10h8pinfuserows[] = { - {12, NO_OUTPUT_ENABLE_FUSE_ROW, 280, 300}, - {13, NO_OUTPUT_ENABLE_FUSE_ROW, 240, 260}, - {14, NO_OUTPUT_ENABLE_FUSE_ROW, 200, 220}, - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 160, 180}, - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 120, 140}, - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 80, 100}, - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 40, 60}, - {19, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 20}}; - -static pin_fuse_rows pal12l6pinfuserows[] = { - {13, NO_OUTPUT_ENABLE_FUSE_ROW, 288, 360}, - {14, NO_OUTPUT_ENABLE_FUSE_ROW, 240, 264}, - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 192, 216}, - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 144, 168}, - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 96, 120}, - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 72}}; - -static pin_fuse_rows pal12h6pinfuserows[] = { - {13, NO_OUTPUT_ENABLE_FUSE_ROW, 288, 360}, - {14, NO_OUTPUT_ENABLE_FUSE_ROW, 240, 264}, - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 192, 216}, - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 144, 168}, - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 96, 120}, - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 72}}; - -static pin_fuse_rows pal14l4pinfuserows[] = { - {14, NO_OUTPUT_ENABLE_FUSE_ROW, 336, 420}, - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 224, 308}, - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 112, 196}, - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 84}}; - -static pin_fuse_rows pal14h4pinfuserows[] = { - {14, NO_OUTPUT_ENABLE_FUSE_ROW, 336, 420}, - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 224, 308}, - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 112, 196}, - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 84}}; - -static pin_fuse_rows pal16l2pinfuserows[] = { - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 256, 480}, - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 224}}; - -static pin_fuse_rows pal16h2pinfuserows[] = { - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 256, 480}, - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 224}}; - -static pin_fuse_rows pal16c1pinfuserows[] = { - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 480}, - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 480}}; - -static pin_fuse_rows pal16l8pinfuserows[] = { - {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}}; - -static pin_fuse_rows pal16r4pinfuserows[] = { - {12, 1792, 1824, 2016}, - {13, 1536, 1568, 1760}, - {14, NO_OUTPUT_ENABLE_FUSE_ROW, 1280, 1504}, /* Registered Output */ - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 1024, 1248}, /* Registered Output */ - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 768, 992}, /* Registered Output */ - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 512, 736}, /* Registered Output */ - {18, 256, 288, 480}, - {19, 0, 32, 224}}; - -static pin_fuse_rows pal16r6pinfuserows[] = { - {12, 1792, 1824, 2016}, - {13, NO_OUTPUT_ENABLE_FUSE_ROW, 1536, 1760}, /* Registered Output */ - {14, NO_OUTPUT_ENABLE_FUSE_ROW, 1280, 1504}, /* Registered Output */ - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 1024, 1248}, /* Registered Output */ - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 768, 992}, /* Registered Output */ - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 512, 736}, /* Registered Output */ - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 256, 480}, /* Registered Output */ - {19, 0, 32, 224}}; - -static pin_fuse_rows pal16r8pinfuserows[] = { - {12, NO_OUTPUT_ENABLE_FUSE_ROW, 1792, 2016}, /* Registered Output */ - {13, NO_OUTPUT_ENABLE_FUSE_ROW, 1536, 1760}, /* Registered Output */ - {14, NO_OUTPUT_ENABLE_FUSE_ROW, 1280, 1504}, /* Registered Output */ - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 1024, 1248}, /* Registered Output */ - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 768, 992}, /* Registered Output */ - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 512, 736}, /* Registered Output */ - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 256, 480}, /* Registered Output */ - {19, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 224}}; /* Registered Output */ - -static pin_fuse_rows gal16v8pinfuserows[] = { - {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 peel18cv8pinfuserows[] = { - {12, 2556, 2016, 2268}, - {13, 2520, 1728, 1980}, - {14, 2484, 1440, 1692}, - {15, 2448, 1152, 1404}, - {16, 2412, 864, 1116}, - {17, 2376, 576, 828}, - {18, 2340, 288, 540}, - {19, 2304, 0, 252}}; - -static pin_fuse_rows ampal18p8pinfuserows[] = { - {12, 2268, 2304, 2556}, - {13, 1944, 1980, 2232}, - {14, 1620, 1656, 1908}, - {15, 1296, 1332, 1584}, - {16, 972, 1008, 1260}, - {17, 648, 684, 936}, - {18, 324, 360, 612}, - {19, 0, 36, 288}}; - -static pin_fuse_rows gal18v10pinfuserows[] = { - {9, 3096, 3132, 3384}, - {11, 2772, 2808, 3060}, - {12, 2448, 2484, 2736}, - {13, 2124, 2160, 2412}, - {14, 1728, 1764, 2088}, - {15, 1332, 1368, 1692}, - {16, 1008, 1044, 1296}, - {17, 684, 720, 972}, - {18, 360, 396, 648}, - {19, 36, 72, 324}}; - -static pin_fuse_rows pal20l8pinfuserows[] = { - {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 pal20l10pinfuserows[] = { - {14, 1440, 1480, 1560}, - {15, 1280, 1320, 1400}, - {16, 1120, 1160, 1240}, - {17, 960, 1000, 1080}, - {18, 800, 840, 920}, - {19, 640, 680, 760}, - {20, 480, 520, 600}, - {21, 320, 360, 440}, - {22, 160, 200, 280}, - {23, 0, 40, 120}}; - -static pin_fuse_rows pal20r4pinfuserows[] = { - {15, 2240, 2280, 2520}, - {16, 1920, 1960, 2200}, - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 1600, 1880}, /* Registered Output */ - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 1280, 1560}, /* Registered Output */ - {19, NO_OUTPUT_ENABLE_FUSE_ROW, 960, 1240}, /* Registered Output */ - {20, NO_OUTPUT_ENABLE_FUSE_ROW, 640, 920}, /* Registered Output */ - {21, 320, 360, 600}, - {22, 0, 40, 280}}; - -static pin_fuse_rows pal20r6pinfuserows[] = { - {15, 2240, 2280, 2520}, - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 1920, 2200}, /* Registered Output */ - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 1600, 1880}, /* Registered Output */ - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 1280, 1560}, /* Registered Output */ - {19, NO_OUTPUT_ENABLE_FUSE_ROW, 960, 1240}, /* Registered Output */ - {20, NO_OUTPUT_ENABLE_FUSE_ROW, 640, 920}, /* Registered Output */ - {21, NO_OUTPUT_ENABLE_FUSE_ROW, 320, 600}, /* Registered Output */ - {22, 0, 40, 280}}; - -static pin_fuse_rows pal20r8pinfuserows[] = { - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 2240, 2520}, /* Registered Output */ - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 1920, 2200}, /* Registered Output */ - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 1600, 1880}, /* Registered Output */ - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 1280, 1560}, /* Registered Output */ - {19, NO_OUTPUT_ENABLE_FUSE_ROW, 960, 1240}, /* Registered Output */ - {20, NO_OUTPUT_ENABLE_FUSE_ROW, 640, 920}, /* Registered Output */ - {21, NO_OUTPUT_ENABLE_FUSE_ROW, 320, 600}, /* Registered Output */ - {22, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 280}}; /* Registered Output */ - -static pin_fuse_rows pal20ra10pinfuserows[] = { - { 14, 0, 0, 0 }, /* Registered Output */ - { 15, 0, 0, 0 }, /* Registered Output */ - { 16, 0, 0, 0 }, /* Registered Output */ - { 17, 0, 0, 0 }, /* Registered Output */ - { 18, 0, 0, 0 }, /* Registered Output */ - { 19, 0, 0, 0 }, /* Registered Output */ - { 20, 0, 0, 0 }, /* Registered Output */ - { 21, 0, 0, 0 }, /* Registered Output */ - { 22, 0, 0, 0 }, /* Registered Output */ - { 23, 0, 0, 0 }}; /* Registered Output */ - -static pin_fuse_rows pal20x4pinfuserows[] = { - {14, 1440, 1480, 1560}, - {15, 1280, 1320, 1400}, - {16, 1120, 1160, 1240}, - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 960, 1080}, /* Registered Output */ - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 800, 920}, /* Registered Output */ - {19, NO_OUTPUT_ENABLE_FUSE_ROW, 640, 760}, /* Registered Output */ - {20, NO_OUTPUT_ENABLE_FUSE_ROW, 480, 600}, /* Registered Output */ - {21, 320, 360, 440}, - {22, 160, 200, 280}, - {23, 0, 40, 120}}; - -static pin_fuse_rows pal20x8pinfuserows[] = { - {14, 1440, 1480, 1560}, - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 1280, 1400}, /* Registered Output */ - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 1120, 1240}, /* Registered Output */ - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 960, 1080}, /* Registered Output */ - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 800, 920}, /* Registered Output */ - {19, NO_OUTPUT_ENABLE_FUSE_ROW, 640, 760}, /* Registered Output */ - {20, NO_OUTPUT_ENABLE_FUSE_ROW, 480, 600}, /* Registered Output */ - {21, NO_OUTPUT_ENABLE_FUSE_ROW, 320, 440}, /* Registered Output */ - {22, NO_OUTPUT_ENABLE_FUSE_ROW, 160, 280}, /* Registered Output */ - {23, 0, 40, 120}}; - -static pin_fuse_rows pal20x10pinfuserows[] = { - {14, NO_OUTPUT_ENABLE_FUSE_ROW, 1440, 1560}, /* Registered Output */ - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 1280, 1400}, /* Registered Output */ - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 1120, 1240}, /* Registered Output */ - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 960, 1080}, /* Registered Output */ - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 800, 920}, /* Registered Output */ - {19, NO_OUTPUT_ENABLE_FUSE_ROW, 640, 760}, /* Registered Output */ - {20, NO_OUTPUT_ENABLE_FUSE_ROW, 480, 600}, /* Registered Output */ - {21, NO_OUTPUT_ENABLE_FUSE_ROW, 320, 440}, /* Registered Output */ - {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}, - {12, 1544, 0, 0}, - {13, 1580, 0, 0}, - {14, 1616, 0, 0}, - {15, 1652, 0, 0}, - {16, 1688, 0, 0}, - {17, 1724, 0, 0}, - {18, 1760, 0, 0}, - {19, 1796, 0, 0}}; - -static pin_fuse_rows ck2605pinfuserows[] = { - {9, 736, 0, 0}, - {11, 772, 0, 0}, - {12, 808, 0, 0}, - {13, 844, 0, 0}, - {14, 880, 0, 0}, - {15, 916, 0, 0}, - {16, 952, 0, 0}, - {17, 988, 0, 0}, - {18, 1024, 0, 0}, - {19, 1060, 0, 0}}; - -#if defined(ricoh_pals) -static pin_fuse_rows epl10p8pinfuserows[] = { - {12, NO_OUTPUT_ENABLE_FUSE_ROW, 560, 620}, - {13, NO_OUTPUT_ENABLE_FUSE_ROW, 480, 540}, - {14, NO_OUTPUT_ENABLE_FUSE_ROW, 400, 460}, - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 320, 380}, - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 240, 300}, - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 160, 220}, - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 80, 140}, - {19, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 60}}; - -static pin_fuse_rows epl12p6pinfuserows[] = { - {13, NO_OUTPUT_ENABLE_FUSE_ROW, 576, 744}, - {14, NO_OUTPUT_ENABLE_FUSE_ROW, 480, 552}, - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 384, 456}, - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 288, 360}, - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 192, 264}, - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 168}}; - -static pin_fuse_rows epl14p4pinfuserows[] = { - {14, NO_OUTPUT_ENABLE_FUSE_ROW, 672, 868}, - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 448, 644}, - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 224, 420}, - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 196}}; - -static pin_fuse_rows epl16p2pinfuserows[] = { - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 512, 992}, - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 480}}; - -static pin_fuse_rows epl16p8pinfuserows[] = { - {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}}; - -static pin_fuse_rows epl16rp8pinfuserows[] = { - {12, NO_OUTPUT_ENABLE_FUSE_ROW, 1792, 2016}, /* Registered Output */ - {13, NO_OUTPUT_ENABLE_FUSE_ROW, 1536, 1760}, /* Registered Output */ - {14, NO_OUTPUT_ENABLE_FUSE_ROW, 1280, 1504}, /* Registered Output */ - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 1024, 1248}, /* Registered Output */ - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 768, 992}, /* Registered Output */ - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 512, 736}, /* Registered Output */ - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 256, 480}, /* Registered Output */ - {19, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 224}}; /* Registered Output */ - -static pin_fuse_rows epl16rp6pinfuserows[] = { - {12, 1792, 1824, 2016}, - {13, NO_OUTPUT_ENABLE_FUSE_ROW, 1536, 1760}, /* Registered Output */ - {14, NO_OUTPUT_ENABLE_FUSE_ROW, 1280, 1504}, /* Registered Output */ - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 1024, 1248}, /* Registered Output */ - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 768, 992}, /* Registered Output */ - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 512, 736}, /* Registered Output */ - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 256, 480}, /* Registered Output */ - {19, 0, 32, 224}}; - -static pin_fuse_rows epl16rp4pinfuserows[] = { - {12, 1792, 1824, 2016}, - {13, 1536, 1568, 1760}, - {14, NO_OUTPUT_ENABLE_FUSE_ROW, 1280, 1504}, /* Registered Output */ - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 1024, 1248}, /* Registered Output */ - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 768, 992}, /* Registered Output */ - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 512, 736}, /* Registered Output */ - {18, 256, 288, 480}, - {19, 0, 32, 224}}; -#endif - -static pin_fuse_rows pal10p8pinfuserows[] = { - {12, NO_OUTPUT_ENABLE_FUSE_ROW, 280, 300}, - {13, NO_OUTPUT_ENABLE_FUSE_ROW, 240, 260}, - {14, NO_OUTPUT_ENABLE_FUSE_ROW, 200, 220}, - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 160, 180}, - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 120, 140}, - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 80, 100}, - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 40, 60}, - {19, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 20}}; - -static pin_fuse_rows pal12p6pinfuserows[] = { - {13, NO_OUTPUT_ENABLE_FUSE_ROW, 288, 360}, - {14, NO_OUTPUT_ENABLE_FUSE_ROW, 240, 264}, - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 192, 216}, - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 144, 168}, - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 96, 120}, - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 72}}; - -static pin_fuse_rows pal14p4pinfuserows[] = { - {14, NO_OUTPUT_ENABLE_FUSE_ROW, 336, 420}, - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 224, 308}, - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 112, 196}, - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 84}}; - -static pin_fuse_rows pal16p2pinfuserows[] = { - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 256, 480}, - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 224}}; - -static pin_fuse_rows pal16p8pinfuserows[] = { - {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}}; - -static pin_fuse_rows pal16rp4pinfuserows[] = { - {12, 1792, 1824, 2016}, - {13, 1536, 1568, 1760}, - {14, NO_OUTPUT_ENABLE_FUSE_ROW, 1280, 1504}, /* Registered Output */ - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 1024, 1248}, /* Registered Output */ - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 768, 992}, /* Registered Output */ - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 512, 736}, /* Registered Output */ - {18, 256, 288, 480}, - {19, 0, 32, 224}}; - -static pin_fuse_rows pal16rp6pinfuserows[] = { - {12, 1792, 1824, 2016}, - {13, NO_OUTPUT_ENABLE_FUSE_ROW, 1536, 1760}, /* Registered Output */ - {14, NO_OUTPUT_ENABLE_FUSE_ROW, 1280, 1504}, /* Registered Output */ - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 1024, 1248}, /* Registered Output */ - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 768, 992}, /* Registered Output */ - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 512, 736}, /* Registered Output */ - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 256, 480}, /* Registered Output */ - {19, 0, 32, 224}}; - -static pin_fuse_rows pal16rp8pinfuserows[] = { - {12, NO_OUTPUT_ENABLE_FUSE_ROW, 1792, 2016}, /* Registered Output */ - {13, NO_OUTPUT_ENABLE_FUSE_ROW, 1536, 1760}, /* Registered Output */ - {14, NO_OUTPUT_ENABLE_FUSE_ROW, 1280, 1504}, /* Registered Output */ - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 1024, 1248}, /* Registered Output */ - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 768, 992}, /* Registered Output */ - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 512, 736}, /* Registered Output */ - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 256, 480}, /* Registered Output */ - {19, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 224}}; /* Registered Output */ - -static pin_fuse_rows pal6l16pinfuserows[] = { - {1, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 0}, - {2, NO_OUTPUT_ENABLE_FUSE_ROW, 24, 24}, - {3, NO_OUTPUT_ENABLE_FUSE_ROW, 36, 36}, - {10, NO_OUTPUT_ENABLE_FUSE_ROW, 132, 132}, - {11, NO_OUTPUT_ENABLE_FUSE_ROW, 168, 168}, - {13, NO_OUTPUT_ENABLE_FUSE_ROW, 180, 180}, - {14, NO_OUTPUT_ENABLE_FUSE_ROW, 156, 156}, - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 144, 144}, - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 120, 120}, - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 108, 108}, - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 96, 96}, - {19, NO_OUTPUT_ENABLE_FUSE_ROW, 84, 84}, - {20, NO_OUTPUT_ENABLE_FUSE_ROW, 72, 72}, - {21, NO_OUTPUT_ENABLE_FUSE_ROW, 60, 60}, - {22, NO_OUTPUT_ENABLE_FUSE_ROW, 48, 48}, - {23, NO_OUTPUT_ENABLE_FUSE_ROW, 12, 12}}; - -static pin_fuse_rows pal8l14pinfuserows[] = { - {1, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 0}, - {2, NO_OUTPUT_ENABLE_FUSE_ROW, 32, 32}, - {11, NO_OUTPUT_ENABLE_FUSE_ROW, 192, 192}, - {13, NO_OUTPUT_ENABLE_FUSE_ROW, 208, 208}, - {14, NO_OUTPUT_ENABLE_FUSE_ROW, 176, 176}, - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 160, 160}, - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 144, 144}, - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 128, 128}, - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 112, 112}, - {19, NO_OUTPUT_ENABLE_FUSE_ROW, 96, 96}, - {20, NO_OUTPUT_ENABLE_FUSE_ROW, 80, 80}, - {21, NO_OUTPUT_ENABLE_FUSE_ROW, 64, 64}, - {22, NO_OUTPUT_ENABLE_FUSE_ROW, 48, 48}, - {23, NO_OUTPUT_ENABLE_FUSE_ROW, 16, 16}}; - -static pin_fuse_rows pal12h10pinfuserows[] = { - {14, NO_OUTPUT_ENABLE_FUSE_ROW, 432, 456}, - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 384, 408}, - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 336, 360}, - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 288, 312}, - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 240, 264}, - {19, NO_OUTPUT_ENABLE_FUSE_ROW, 192, 216}, - {20, NO_OUTPUT_ENABLE_FUSE_ROW, 144, 168}, - {21, NO_OUTPUT_ENABLE_FUSE_ROW, 96, 120}, - {22, NO_OUTPUT_ENABLE_FUSE_ROW, 48, 72}, - {23, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 24}}; - -static pin_fuse_rows pal12l10pinfuserows[] = { - {14, NO_OUTPUT_ENABLE_FUSE_ROW, 432, 456}, - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 384, 408}, - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 336, 360}, - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 288, 312}, - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 240, 264}, - {19, NO_OUTPUT_ENABLE_FUSE_ROW, 192, 216}, - {20, NO_OUTPUT_ENABLE_FUSE_ROW, 144, 168}, - {21, NO_OUTPUT_ENABLE_FUSE_ROW, 96, 120}, - {22, NO_OUTPUT_ENABLE_FUSE_ROW, 48, 72}, - {23, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 24}}; - -static pin_fuse_rows pal14h8pinfuserows[] = { - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 448, 532}, - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 392, 420}, - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 336, 364}, - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 280, 308}, - {19, NO_OUTPUT_ENABLE_FUSE_ROW, 224, 252}, - {20, NO_OUTPUT_ENABLE_FUSE_ROW, 168, 196}, - {21, NO_OUTPUT_ENABLE_FUSE_ROW, 112, 140}, - {22, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 84}}; - -static pin_fuse_rows pal14l8pinfuserows[] = { - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 448, 532}, - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 392, 420}, - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 336, 364}, - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 280, 308}, - {19, NO_OUTPUT_ENABLE_FUSE_ROW, 224, 252}, - {20, NO_OUTPUT_ENABLE_FUSE_ROW, 168, 196}, - {21, NO_OUTPUT_ENABLE_FUSE_ROW, 112, 140}, - {22, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 84}}; - -static pin_fuse_rows pal16h6pinfuserows[] = { - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 512, 608}, - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 384, 480}, - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 320, 352}, - {19, NO_OUTPUT_ENABLE_FUSE_ROW, 256, 288}, - {20, NO_OUTPUT_ENABLE_FUSE_ROW, 128, 224}, - {21, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 96}}; - -static pin_fuse_rows pal16l6pinfuserows[] = { - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 512, 608}, - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 384, 480}, - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 320, 352}, - {19, NO_OUTPUT_ENABLE_FUSE_ROW, 256, 288}, - {20, NO_OUTPUT_ENABLE_FUSE_ROW, 128, 224}, - {21, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 96}}; - -static pin_fuse_rows pal18h4pinfuserows[] = { - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 504, 684}, - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 360, 468}, - {19, NO_OUTPUT_ENABLE_FUSE_ROW, 216, 324}, - {20, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 180}}; - -static pin_fuse_rows pal18l4pinfuserows[] = { - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 504, 684}, - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 360, 468}, - {19, NO_OUTPUT_ENABLE_FUSE_ROW, 216, 324}, - {20, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 180}}; - -static pin_fuse_rows pal20c1pinfuserows[] = { - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 280}, - {19, NO_OUTPUT_ENABLE_FUSE_ROW, 320, 600}}; - -static pin_fuse_rows pal20l2pinfuserows[] = { - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 320, 600}, - {19, NO_OUTPUT_ENABLE_FUSE_ROW, 0, 280}}; - -static pin_fuse_rows _82s100_pls100_pinfuserows[] = { - {18, NO_OUTPUT_ENABLE_FUSE_ROW, 0}, - {17, NO_OUTPUT_ENABLE_FUSE_ROW, 0}, - {16, NO_OUTPUT_ENABLE_FUSE_ROW, 0}, - {15, NO_OUTPUT_ENABLE_FUSE_ROW, 0}, - {13, NO_OUTPUT_ENABLE_FUSE_ROW, 0}, - {12, NO_OUTPUT_ENABLE_FUSE_ROW, 0}, - {11, NO_OUTPUT_ENABLE_FUSE_ROW, 0}, - {10, NO_OUTPUT_ENABLE_FUSE_ROW, 0}}; - -static pin_fuse_columns pal10l8pinfusecolumns[] = { - {1, 3, 2}, - {2, 1, 0}, - {3, 5, 4}, - {4, 7, 6}, - {5, 9, 8}, - {6, 11, 10}, - {7, 13, 12}, - {8, 15, 14}, - {9, 17, 16}, - {11, 19, 18}}; - -static pin_fuse_columns pal10h8pinfusecolumns[] = { - {1, 3, 2}, - {2, 1, 0}, - {3, 5, 4}, - {4, 7, 6}, - {5, 9, 8}, - {6, 11, 10}, - {7, 13, 12}, - {8, 15, 14}, - {9, 17, 16}, - {11, 19, 18}}; - -static pin_fuse_columns pal12l6pinfusecolumns[] = { - {1, 3, 2}, - {2, 1, 0}, - {3, 5, 4}, - {4, 9, 8}, - {5, 11, 10}, - {6, 13, 12}, - {7, 15, 14}, - {8, 17, 16}, - {9, 21, 20}, - {11, 23, 22}, - {12, 19, 18}, - {19, 7, 6}}; - -static pin_fuse_columns pal12h6pinfusecolumns[] = { - {1, 3, 2}, - {2, 1, 0}, - {3, 5, 4}, - {4, 9, 8}, - {5, 11, 10}, - {6, 13, 12}, - {7, 15, 14}, - {8, 17, 16}, - {9, 21, 20}, - {11, 23, 22}, - {12, 19, 18}, - {19, 7, 6}}; - -static pin_fuse_columns pal14l4pinfusecolumns[] = { - {1, 3, 2}, - {2, 1, 0}, - {3, 5, 4}, - {4, 9, 8}, - {5, 13, 12}, - {6, 15, 14}, - {7, 17, 16}, - {8, 21, 20}, - {9, 25, 24}, - {11, 27, 26}, - {12, 23, 22}, - {13, 19, 18}, - {18, 11, 10}, - {19, 7, 6}}; - -static pin_fuse_columns pal14h4pinfusecolumns[] = { - {1, 3, 2}, - {2, 1, 0}, - {3, 5, 4}, - {4, 9, 8}, - {5, 13, 12}, - {6, 15, 14}, - {7, 17, 16}, - {8, 21, 20}, - {9, 25, 24}, - {11, 27, 26}, - {12, 23, 22}, - {13, 19, 18}, - {18, 11, 10}, - {19, 7, 6}}; - -static pin_fuse_columns pal16l2pinfusecolumns[] = { - {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 pal16h2pinfusecolumns[] = { - {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 pal16c1pinfusecolumns[] = { - {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 pal16l8pinfusecolumns[] = { - {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 pal16r4pinfusecolumns[] = { - {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}, /* Registered Output */ - {15, 19, 18}, /* Registered Output */ - {16, 15, 14}, /* Registered Output */ - {17, 11, 10}, /* Registered Output */ - {18, 7, 6}, - {19, 3, 2}}; - -static pin_fuse_columns pal16r6pinfusecolumns[] = { - {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}, /* Registered Output */ - {14, 23, 22}, /* Registered Output */ - {15, 19, 18}, /* Registered Output */ - {16, 15, 14}, /* Registered Output */ - {17, 11, 10}, /* Registered Output */ - {18, 7, 6}, /* Registered Output */ - {19, 3, 2}}; - -static pin_fuse_columns pal16r8pinfusecolumns[] = { - {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}, /* Registered Output */ - {13, 27, 26}, /* Registered Output */ - {14, 23, 22}, /* Registered Output */ - {15, 19, 18}, /* Registered Output */ - {16, 15, 14}, /* Registered Output */ - {17, 11, 10}, /* Registered Output */ - {18, 7, 6}, /* Registered Output */ - {19, 3, 2}}; /* Registered Output */ - -static pin_fuse_columns gal16v8pinfusecolumns[] = { - {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 peel18cv8pinfusecolumns[] = { - {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}, - {11, 3, 2}, - {12, 35, 34}, - {13, 31, 30}, - {14, 27, 26}, - {15, 23, 22}, - {16, 19, 18}, - {17, 15, 14}, - {18, 11, 10}, - {19, 7, 6}}; - -static pin_fuse_columns ampal18p8pinfusecolumns[] = { - {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, 35, 34}, - {13, 27, 26}, - {14, 23, 22}, - {15, 19, 18}, - {16, 15, 14}, - {17, 11, 10}, - {18, 7, 6}, - {19, 33, 32}}; - -static pin_fuse_columns gal18v10pinfusecolumns[] = { - {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, 35, 34}, - {11, 33, 32}, - {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 pal20l8pinfusecolumns[] = { - {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 pal20l10pinfusecolumns[] = { - {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}, - {15, 35, 34}, - {16, 31, 30}, - {17, 27, 26}, - {18, 23, 22}, - {19, 19, 18}, - {20, 15, 14}, - {21, 11, 10}, - {22, 7, 6}}; - -static pin_fuse_columns pal20r4pinfusecolumns[] = { - {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 pal20r6pinfusecolumns[] = { - {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 pal20r8pinfusecolumns[] = { - {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 pal20ra10pinfusecolumns[] = { - {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 pal20x4pinfusecolumns[] = { - {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 pal20x8pinfusecolumns[] = { - {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 pal20x10pinfusecolumns[] = { - {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 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}, - {3, 5, 4}, - {4, 7, 6}, - {5, 9, 8}, - {6, 11, 10}, - {7, 13, 12}, - {8, 15, 14}, - {9, 17, 16}, - {11, 19, 18}, - {12, 21, 20}, - {13, 23, 22}, - {14, 25, 24}, - {15, 27, 26}, - {16, 29, 28}, - {17, 31, 30}, - {18, 33, 32}, - {19, 35, 34}}; - -static pin_fuse_columns ck2605pinfusecolumns[] = { - {1, 1, 0}, - {2, 3, 2}, - {3, 5, 4}, - {4, 7, 6}, - {5, 9, 8}, - {6, 11, 10}, - {7, 13, 12}, - {8, 15, 14}, - {9, 17, 16}, - {11, 19, 18}, - {12, 21, 20}, - {13, 23, 22}, - {14, 25, 24}, - {15, 27, 26}, - {16, 29, 28}, - {17, 31, 30}, - {18, 33, 32}, - {19, 35, 34}}; - -#if defined(ricoh_pals) -static pin_fuse_columns epl10p8pinfusecolumns[] = { - {1, 3, 2}, - {2, 1, 0}, - {3, 5, 4}, - {4, 7, 6}, - {5, 9, 8}, - {6, 11, 10}, - {7, 13, 12}, - {8, 15, 14}, - {9, 17, 16}, - {11, 19, 18}}; - -static pin_fuse_columns epl12p6pinfusecolumns[] = { - {1, 3, 2}, - {2, 1, 0}, - {3, 5, 4}, - {4, 9, 8}, - {5, 11, 10}, - {6, 13, 12}, - {7, 15, 14}, - {8, 17, 16}, - {9, 19, 18}, - {11, 21, 20}, - {12, 19, 18}, - {19, 7, 6}}; - -static pin_fuse_columns epl14p4pinfusecolumns[] = { - {1, 3, 2}, - {2, 1, 0}, - {3, 5, 4}, - {4, 9, 8}, - {5, 13, 12}, - {6, 15, 14}, - {7, 17, 16}, - {8, 21, 20}, - {9, 25, 24}, - {11, 27, 26}, - {12, 23, 22}, - {13, 19, 18}, - {18, 11, 10}, - {19, 7, 6}}; - -static pin_fuse_columns epl16p2pinfusecolumns[] = { - {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 epl16p8pinfusecolumns[] = { - {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 epl16rp8pinfusecolumns[] = { - {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 epl16rp6pinfusecolumns[] = { - {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 epl16rp4pinfusecolumns[] = { - {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}, - {18, 7, 6}, - {19, 3, 2}}; -#endif - -static pin_fuse_columns pal10p8pinfusecolumns[] = { - {1, 3, 2}, - {2, 1, 0}, - {3, 5, 4}, - {4, 7, 6}, - {5, 9, 8}, - {6, 11, 10}, - {7, 13, 12}, - {8, 15, 14}, - {9, 17, 16}, - {11, 19, 18}}; - -static pin_fuse_columns pal12p6pinfusecolumns[] = { - {1, 3, 2}, - {2, 1, 0}, - {3, 5, 4}, - {4, 9, 8}, - {5, 11, 10}, - {6, 13, 12}, - {7, 15, 14}, - {8, 17, 16}, - {9, 21, 20}, - {11, 23, 22}, - {12, 19, 18}, - {19, 7, 6}}; - -static pin_fuse_columns pal14p4pinfusecolumns[] = { - {1, 3, 2}, - {2, 1, 0}, - {3, 5, 4}, - {4, 9, 8}, - {5, 13, 12}, - {6, 15, 14}, - {7, 17, 16}, - {8, 21, 20}, - {9, 25, 24}, - {11, 27, 26}, - {12, 23, 22}, - {13, 19, 18}, - {18, 11, 10}, - {19, 7, 6}}; - -static pin_fuse_columns pal16p2pinfusecolumns[] = { - {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 pal16p8pinfusecolumns[] = { - {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 pal16rp4pinfusecolumns[] = { - {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}, /* Registered Output */ - {15, 19, 18}, /* Registered Output */ - {16, 15, 14}, /* Registered Output */ - {17, 11, 10}, /* Registered Output */ - {18, 7, 6}, - {19, 3, 2}}; - -static pin_fuse_columns pal16rp6pinfusecolumns[] = { - {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}, /* Registered Output */ - {14, 23, 22}, /* Registered Output */ - {15, 19, 18}, /* Registered Output */ - {16, 15, 14}, /* Registered Output */ - {17, 11, 10}, /* Registered Output */ - {18, 7, 6}, /* Registered Output */ - {19, 3, 2}}; - -static pin_fuse_columns pal16rp8pinfusecolumns[] = { - {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}, /* Registered Output */ - {13, 27, 26}, /* Registered Output */ - {14, 23, 22}, /* Registered Output */ - {15, 19, 18}, /* Registered Output */ - {16, 15, 14}, /* Registered Output */ - {17, 11, 10}, /* Registered Output */ - {18, 7, 6}, /* Registered Output */ - {19, 3, 2}}; /* Registered Output */ - -static pin_fuse_columns pal6l16pinfusecolumns[] = { - {4, 1, 0}, - {5, 3, 2}, - {6, 5, 4}, - {7, 7, 6}, - {8, 9, 8}, - {9, 11, 10}}; - -static pin_fuse_columns pal8l14pinfusecolumns[] = { - {3, 1, 0}, - {4, 3, 2}, - {5, 5, 4}, - {6, 7, 6}, - {7, 9, 8}, - {8, 11, 10}, - {9, 13, 12}, - {10, 15, 14}}; - -static pin_fuse_columns pal12h10pinfusecolumns[] = { - {1, 3, 2}, - {2, 1, 0}, - {3, 5, 4}, - {4, 7, 6}, - {5, 9, 8}, - {6, 11, 10}, - {7, 13, 12}, - {8, 15, 14}, - {9, 17, 16}, - {10, 19, 18}, - {11, 21, 20}, - {13, 23, 22}}; - -static pin_fuse_columns pal12l10pinfusecolumns[] = { - {1, 3, 2}, - {2, 1, 0}, - {3, 5, 4}, - {4, 7, 6}, - {5, 9, 8}, - {6, 11, 10}, - {7, 13, 12}, - {8, 15, 14}, - {9, 17, 16}, - {10, 19, 18}, - {11, 21, 20}, - {13, 23, 22}}; - -static pin_fuse_columns pal14h8pinfusecolumns[] = { - {1, 3, 2}, - {2, 1, 0}, - {3, 5, 4}, - {4, 9, 8}, - {5, 11, 10}, - {6, 13, 12}, - {7, 15, 14}, - {8, 17, 16}, - {9, 19, 18}, - {10, 21, 20}, - {11, 25, 24}, - {13, 27, 26}, - {14, 23, 22}, - {23, 7, 6}}; - -static pin_fuse_columns pal14l8pinfusecolumns[] = { - {1, 3, 2}, - {2, 1, 0}, - {3, 5, 4}, - {4, 9, 8}, - {5, 11, 10}, - {6, 13, 12}, - {7, 15, 14}, - {8, 17, 16}, - {9, 19, 18}, - {10, 21, 20}, - {11, 25, 24}, - {13, 27, 26}, - {14, 23, 22}, - {23, 7, 6}}; - -static pin_fuse_columns pal16h6pinfusecolumns[] = { - {1, 3, 2}, - {2, 1, 0}, - {3, 5, 4}, - {4, 9, 8}, - {5, 13, 12}, - {6, 15, 14}, - {7, 17, 16}, - {8, 19, 18}, - {9, 21, 20}, - {10, 25, 24}, - {11, 29, 28}, - {13, 31, 30}, - {14, 27, 26}, - {15, 23, 22}, - {22, 11, 10}, - {23, 7, 6}}; - -static pin_fuse_columns pal16l6pinfusecolumns[] = { - {1, 3, 2}, - {2, 1, 0}, - {3, 5, 4}, - {4, 9, 8}, - {5, 13, 12}, - {6, 15, 14}, - {7, 17, 16}, - {8, 19, 18}, - {9, 21, 20}, - {10, 25, 24}, - {11, 29, 28}, - {13, 31, 30}, - {14, 27, 26}, - {15, 23, 22}, - {22, 11, 10}, - {23, 7, 6}}; - -static pin_fuse_columns pal18h4pinfusecolumns[] = { - {1, 3, 2}, - {2, 1, 0}, - {3, 5, 4}, - {4, 9, 8}, - {5, 13, 12}, - {6, 17, 16}, - {7, 19, 18}, - {8, 21, 20}, - {9, 25, 24}, - {10, 29, 28}, - {11, 33, 32}, - {13, 35, 34}, - {14, 31, 30}, - {15, 27, 26}, - {16, 23, 22}, - {21, 15, 14}, - {22, 11, 10}, - {23, 7, 6}}; - -static pin_fuse_columns pal18l4pinfusecolumns[] = { - {1, 3, 2}, - {2, 1, 0}, - {3, 5, 4}, - {4, 9, 8}, - {5, 13, 12}, - {6, 17, 16}, - {7, 19, 18}, - {8, 21, 20}, - {9, 25, 24}, - {10, 29, 28}, - {11, 33, 32}, - {13, 35, 34}, - {14, 31, 30}, - {15, 27, 26}, - {16, 23, 22}, - {21, 15, 14}, - {22, 11, 10}, - {23, 7, 6}}; - -static pin_fuse_columns pal20c1pinfusecolumns[] = { - {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 pin_fuse_columns pal20l2pinfusecolumns[] = { - {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 pin_fuse_columns _82s100_pls100_pinfusecolumns[] = { - {9, 1, 0}, - {8, 3, 2}, - {7, 5, 4}, - {6, 7, 6}, - {5, 9, 8}, - {4, 11, 10}, - {3, 13, 12}, - {2, 15, 14}, - {27, 17, 16}, - {26, 19, 18}, - {25, 21, 20}, - {24, 23, 22}, - {23, 25, 24}, - {22, 27, 26}, - {21, 29, 28}, - {20, 31, 30}}; - -static pal_data paldata[] = { - {"PAL10L8", 320, - pal10l8pinfuserows, std::size(pal10l8pinfuserows), - pal10l8pinfusecolumns, std::size(pal10l8pinfusecolumns), - print_pal10l8_product_terms, - config_pal10l8_pins, - nullptr, - nullptr}, - {"PAL10H8", 320, - pal10h8pinfuserows, std::size(pal10h8pinfuserows), - pal10h8pinfusecolumns, std::size(pal10h8pinfusecolumns), - print_pal10h8_product_terms, - config_pal10h8_pins, - nullptr, - nullptr}, - {"PAL12H6", 384, - pal12h6pinfuserows, std::size(pal12h6pinfuserows), - pal12h6pinfusecolumns, std::size(pal12h6pinfusecolumns), - print_pal12h6_product_terms, - config_pal12h6_pins, - nullptr, - nullptr}, - {"PAL14H4", 448, - pal14h4pinfuserows, std::size(pal14h4pinfuserows), - pal14h4pinfusecolumns, std::size(pal14h4pinfusecolumns), - print_pal14h4_product_terms, - config_pal14h4_pins, - nullptr, - nullptr}, - {"PAL16H2", 512, - pal16h2pinfuserows, std::size(pal16h2pinfuserows), - pal16h2pinfusecolumns, std::size(pal16h2pinfusecolumns), - print_pal16h2_product_terms, - config_pal16h2_pins, - nullptr, - nullptr}, - {"PAL16C1", 512, - pal16c1pinfuserows, std::size(pal16c1pinfuserows), - pal16c1pinfusecolumns, std::size(pal16c1pinfusecolumns), - print_pal16c1_product_terms, - config_pal16c1_pins, - nullptr, - nullptr}, - {"PAL12L6", 384, - pal12l6pinfuserows, std::size(pal12l6pinfuserows), - pal12l6pinfusecolumns, std::size(pal12l6pinfusecolumns), - print_pal12l6_product_terms, - config_pal12l6_pins, - nullptr, - nullptr}, - {"PAL14L4", 448, - pal14l4pinfuserows, std::size(pal14l4pinfuserows), - pal14l4pinfusecolumns, std::size(pal14l4pinfusecolumns), - print_pal14l4_product_terms, - config_pal14l4_pins, - nullptr, - nullptr}, - {"PAL16L2", 512, - 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, std::size(pal16l8pinfuserows), - pal16l8pinfusecolumns, std::size(pal16l8pinfusecolumns), - print_pal16l8_product_terms, - config_pal16l8_pins, - nullptr, - nullptr}, - {"PAL16R4", 2048, - pal16r4pinfuserows, std::size(pal16r4pinfuserows), - pal16r4pinfusecolumns, std::size(pal16r4pinfusecolumns), - print_pal16r4_product_terms, - config_pal16r4_pins, - nullptr, - nullptr}, - {"PAL16R6", 2048, - pal16r6pinfuserows, std::size(pal16r6pinfuserows), - pal16r6pinfusecolumns, std::size(pal16r6pinfusecolumns), - print_pal16r6_product_terms, - config_pal16r6_pins, - nullptr, - nullptr}, - {"PAL16R8", 2048, - 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},*/ // PAL16V8 same fusemap as GAL16V8? - {"PALCE16V8", 2194, - gal16v8pinfuserows, std::size(gal16v8pinfuserows), - gal16v8pinfusecolumns, std::size(gal16v8pinfusecolumns), - print_gal16v8_product_terms, - config_gal16v8_pins, - nullptr, - nullptr}, - {"GAL16V8", 2194, - 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, std::size(peel18cv8pinfuserows), - peel18cv8pinfusecolumns, std::size(peel18cv8pinfusecolumns), - print_peel18cv8_product_terms, - config_peel18cv8_pins, - nullptr, - get_peel18cv8_pin_fuse_state}, - {"AMPAL18P8", 2600, - ampal18p8pinfuserows, std::size(ampal18p8pinfuserows), - ampal18p8pinfusecolumns, std::size(ampal18p8pinfusecolumns), - print_ampal18p8_product_terms, - config_ampal18p8_pins, - nullptr, - nullptr}, - {"GAL18V10", 3540, - gal18v10pinfuserows, std::size(gal18v10pinfuserows), - gal18v10pinfusecolumns, std::size(gal18v10pinfusecolumns), - print_gal18v10_product_terms, - config_gal18v10_pins, - nullptr, - nullptr}, - {"PAL20L8", 2560, - pal20l8pinfuserows, std::size(pal20l8pinfuserows), - pal20l8pinfusecolumns, std::size(pal20l8pinfusecolumns), - print_pal20l8_product_terms, - config_pal20l8_pins, - nullptr, - nullptr}, - {"PAL20L10", 1600, - pal20l10pinfuserows, std::size(pal20l10pinfuserows), - pal20l10pinfusecolumns, std::size(pal20l10pinfusecolumns), - print_pal20l10_product_terms, - config_pal20l10_pins, - nullptr, - nullptr}, - {"PAL20R4", 2560, - pal20r4pinfuserows, std::size(pal20r4pinfuserows), - pal20r4pinfusecolumns, std::size(pal20r4pinfusecolumns), - print_pal20r4_product_terms, - config_pal20r4_pins, - nullptr, - nullptr}, - {"PAL20R6", 2560, - pal20r6pinfuserows, std::size(pal20r6pinfuserows), - pal20r6pinfusecolumns, std::size(pal20r6pinfusecolumns), - print_pal20r6_product_terms, - config_pal20r6_pins, - nullptr, - nullptr}, - {"PAL20R8", 2560, - pal20r8pinfuserows, std::size(pal20r8pinfuserows), - pal20r8pinfusecolumns, std::size(pal20r8pinfusecolumns), - print_pal20r8_product_terms, - config_pal20r8_pins, - nullptr, - nullptr}, - {"PAL20RA10", 3210, - pal20ra10pinfuserows, std::size(pal20ra10pinfuserows), - pal20ra10pinfusecolumns, std::size(pal20ra10pinfusecolumns), - print_pal20ra10_product_terms, - config_pal20ra10_pins, - nullptr, - nullptr }, - {"PAL20X4", 1600, - pal20x4pinfuserows, std::size(pal20x4pinfuserows), - pal20x4pinfusecolumns, std::size(pal20x4pinfusecolumns), - print_pal20x4_product_terms, - config_pal20x4_pins, - nullptr, - nullptr}, - {"PAL20X8", 1600, - pal20x8pinfuserows, std::size(pal20x8pinfuserows), - pal20x8pinfusecolumns, std::size(pal20x8pinfusecolumns), - print_pal20x8_product_terms, - config_pal20x8_pins, - nullptr, - nullptr}, - {"PAL20X10", 1600, - pal20x10pinfuserows, std::size(pal20x10pinfuserows), - pal20x10pinfusecolumns, std::size(pal20x10pinfusecolumns), - print_pal20x10_product_terms, - config_pal20x10_pins, - nullptr, - nullptr}, - {"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, 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, std::size(_82s153_pls153pinfuserows), - _82s153_pls153pinfusecolumns, std::size(_82s153_pls153pinfusecolumns), - print_82s153_pls153_product_terms, - config_82s153_pls153_pins, - nullptr, - nullptr}, - {"CK2605", 1106, - ck2605pinfuserows, std::size(ck2605pinfuserows), - ck2605pinfusecolumns, std::size(ck2605pinfusecolumns), - print_ck2605_product_terms, - config_ck2605_pins, - nullptr, - nullptr}, -#if defined(ricoh_pals) - {"EPL10P8", 664, - epl10p8pinfuserows, std::size(epl10p8pinfuserows), - epl10p8pinfusecolumns, std::size(epl10p8pinfusecolumns), - print_epl10p8_product_terms, - config_epl10p8_pins, - nullptr, - nullptr}, - {"EPL12P6", 786, - epl12p6pinfuserows, std::size(epl12p6pinfuserows), - epl12p6pinfusecolumns, std::size(epl12p6pinfusecolumns), - print_epl12p6_product_terms, - config_epl12p6_pins, - nullptr, - nullptr}, - {"EPL14P4", 908, - epl14p4pinfuserows, std::size(epl14p4pinfuserows), - epl14p4pinfusecolumns, std::size(epl14p4pinfusecolumns), - print_epl14p4_product_terms, - config_epl14p4_pins, - nullptr, - nullptr}, - {"EPL16P2", 1030, - epl16p2pinfuserows, std::size(epl16p2pinfuserows), - epl16p2pinfusecolumns, std::size(epl16p2pinfusecolumns), - print_epl16p2_product_terms, - config_epl16p2_pins, - nullptr, - nullptr}, - {"EPL16P8", 2072, - epl16p8pinfuserows, std::size(epl16p8pinfuserows), - epl16p8pinfusecolumns, std::size(epl16p8pinfusecolumns), - print_epl16p8_product_terms, - config_epl16p8_pins, - nullptr, - nullptr}, - {"EPL16RP8", 2072, - epl16rp8pinfuserows, std::size(epl16rp8pinfuserows), - epl16rp8pinfusecolumns, std::size(epl16rp8pinfusecolumns), - print_epl16rp8_product_terms, - config_epl16rp8_pins, - nullptr, - nullptr}, - {"EPL16RP6", 2072, - epl16rp6pinfuserows, std::size(epl16rp6pinfuserows), - epl16rp6pinfusecolumns, std::size(epl16rp6pinfusecolumns), - print_epl16rp6_product_terms, - config_epl16rp6_pins, - nullptr, - nullptr}, - {"EPL16RP4", 2072, - epl16rp4pinfuserows, std::size(epl16rp4pinfuserows), - epl16rp4pinfusecolumns, std::size(epl16rp4pinfusecolumns), - print_epl16rp4_product_terms, - config_epl16rp4_pins, - nullptr, - nullptr}, -#endif - {"PAL10P8", 328, - pal10p8pinfuserows, std::size(pal10p8pinfuserows), - pal10p8pinfusecolumns, std::size(pal10p8pinfusecolumns), - print_pal10p8_product_terms, - config_pal10p8_pins, - nullptr, - nullptr}, - {"PAL12P6", 390, - pal12p6pinfuserows, std::size(pal12p6pinfuserows), - pal12p6pinfusecolumns, std::size(pal12p6pinfusecolumns), - print_pal12p6_product_terms, - config_pal12p6_pins, - nullptr, - nullptr}, - {"PAL14P4", 452, - pal14p4pinfuserows, std::size(pal14p4pinfuserows), - pal14p4pinfusecolumns, std::size(pal14p4pinfusecolumns), - print_pal14p4_product_terms, - config_pal14p4_pins, - nullptr, - nullptr}, - {"PAL16P2", 514, - pal16p2pinfuserows, std::size(pal16p2pinfuserows), - pal16p2pinfusecolumns, std::size(pal16p2pinfusecolumns), - print_pal16p2_product_terms, - config_pal16p2_pins, - nullptr, - nullptr}, - {"PAL16P8", 2056, - pal16p8pinfuserows, std::size(pal16p8pinfuserows), - pal16p8pinfusecolumns, std::size(pal16p8pinfusecolumns), - print_pal16p8_product_terms, - config_pal16p8_pins, - nullptr, - nullptr}, - {"PAL16RP4", 2056, - pal16rp4pinfuserows, std::size(pal16rp4pinfuserows), - pal16rp4pinfusecolumns, std::size(pal16rp4pinfusecolumns), - print_pal16rp4_product_terms, - config_pal16rp4_pins, - nullptr, - nullptr}, - {"PAL16RP6", 2056, - pal16rp6pinfuserows, std::size(pal16rp6pinfuserows), - pal16rp6pinfusecolumns, std::size(pal16rp6pinfusecolumns), - print_pal16rp6_product_terms, - config_pal16rp6_pins, - nullptr, - nullptr}, - {"PAL16RP8", 2056, - pal16rp8pinfuserows, std::size(pal16rp8pinfuserows), - pal16rp8pinfusecolumns, std::size(pal16rp8pinfusecolumns), - print_pal16rp8_product_terms, - config_pal16rp8_pins, - nullptr, - nullptr}, - {"PAL6L16", 192, - pal6l16pinfuserows, std::size(pal6l16pinfuserows), - pal6l16pinfusecolumns, std::size(pal6l16pinfusecolumns), - print_pal6l16_product_terms, - config_pal6l16_pins, - nullptr, - nullptr}, - {"PAL8L14", 224, - pal8l14pinfuserows, std::size(pal8l14pinfuserows), - pal8l14pinfusecolumns, std::size(pal8l14pinfusecolumns), - print_pal8l14_product_terms, - config_pal8l14_pins, - nullptr, - nullptr}, - {"PAL12H10", 480, - pal12h10pinfuserows, std::size(pal12h10pinfuserows), - pal12h10pinfusecolumns, std::size(pal12h10pinfusecolumns), - print_pal12h10_product_terms, - config_pal12h10_pins, - nullptr, - nullptr}, - {"PAL12L10", 480, - pal12l10pinfuserows, std::size(pal12l10pinfuserows), - pal12l10pinfusecolumns, std::size(pal12l10pinfusecolumns), - print_pal12l10_product_terms, - config_pal12l10_pins, - nullptr, - nullptr}, - {"PAL14H8", 560, - pal14h8pinfuserows, std::size(pal14h8pinfuserows), - pal14h8pinfusecolumns, std::size(pal14h8pinfusecolumns), - print_pal14h8_product_terms, - config_pal14h8_pins, - nullptr, - nullptr}, - {"PAL14L8", 560, - pal14l8pinfuserows, std::size(pal14l8pinfuserows), - pal14l8pinfusecolumns, std::size(pal14l8pinfusecolumns), - print_pal14l8_product_terms, - config_pal14l8_pins, - nullptr, - nullptr}, - {"PAL16H6", 640, - pal16h6pinfuserows, std::size(pal16h6pinfuserows), - pal16h6pinfusecolumns, std::size(pal16h6pinfusecolumns), - print_pal16h6_product_terms, - config_pal16h6_pins, - nullptr, - nullptr}, - {"PAL16L6", 640, - pal16l6pinfuserows, std::size(pal16l6pinfuserows), - pal16l6pinfusecolumns, std::size(pal16l6pinfusecolumns), - print_pal16l6_product_terms, - config_pal16l6_pins, - nullptr, - nullptr}, - {"PAL18H4", 720, - pal18h4pinfuserows, std::size(pal18h4pinfuserows), - pal18h4pinfusecolumns, std::size(pal18h4pinfusecolumns), - print_pal18h4_product_terms, - config_pal18h4_pins, - nullptr, - nullptr}, - {"PAL18L4", 720, - pal18l4pinfuserows, std::size(pal18l4pinfuserows), - pal18l4pinfusecolumns, std::size(pal18l4pinfusecolumns), - print_pal18l4_product_terms, - config_pal18l4_pins, - nullptr, - nullptr}, - {"PAL20C1", 640, - pal20c1pinfuserows, std::size(pal20c1pinfuserows), - pal20c1pinfusecolumns, std::size(pal20c1pinfusecolumns), - print_pal20c1_product_terms, - config_pal20c1_pins, - nullptr, - nullptr}, - {"PAL20L2", 640, - pal20l2pinfuserows, std::size(pal20l2pinfuserows), - pal20l2pinfusecolumns, std::size(pal20l2pinfusecolumns), - print_pal20l2_product_terms, - config_pal20l2_pins, - nullptr, - nullptr}, - {"82S100", 1928, - _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, 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, 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, std::size(_82s100_pls100_pinfuserows), - _82s100_pls100_pinfusecolumns, std::size(_82s100_pls100_pinfusecolumns), - print_82s100_pls100_product_terms, - config_82s100_pls100_pins, - nullptr, - nullptr}}; - -/*************************************************************************** - CORE IMPLEMENTATION -***************************************************************************/ - -/*------------------------------------------------- - is_jed_file - test if the file extension is - that of a JED file --------------------------------------------------*/ - -static int is_jed_file(const char *file) -{ - int len; - - /* does the source end in '.jed'? */ - len = strlen(file); - - return (file[len - 4] == '.' && - tolower((uint8_t)file[len - 3]) == 'j' && - tolower((uint8_t)file[len - 2]) == 'e' && - tolower((uint8_t)file[len - 1]) == 'd'); -} - - - -/*------------------------------------------------- - is_pla_file - test if the file extension is - that of a Berkeley standard PLA file --------------------------------------------------*/ - -static int is_pla_file(const char *file) -{ - int len; - - /* does the source end in '.pla'? */ - len = strlen(file); - - return (file[len - 4] == '.' && - tolower((uint8_t)file[len - 3]) == 'p' && - tolower((uint8_t)file[len - 2]) == 'l' && - tolower((uint8_t)file[len - 1]) == 'a'); -} - - - -/*------------------------------------------------- - find_pal_data - finds the data associated - with a pal name --------------------------------------------------*/ - -static void find_pal_data(const char *name, pal_data_vector& pal_data_vector) -{ - int index; - - for (index = 0; index < std::size(paldata); ++index) - { - if (!core_stricmp(name, paldata[index].name)) - { - pal_data_vector.push_back(&paldata[index]); - } - } -} - - - -/*------------------------------------------------- - find_fuse_rows - finds the fuse row data for - an output pin. --------------------------------------------------*/ - -static const pin_fuse_rows* find_fuse_rows(const pal_data* pal, uint16_t pin) -{ - uint16_t index; - - for (index = 0; index < pal->pinfuserowscount; ++index) - { - if (pal->pinfuserows[index].pin == pin) - { - return &pal->pinfuserows[index]; - } - } - - return nullptr; -} - - - -/*------------------------------------------------- - find_fuse_columns - finds the fuse column - data for an input pin. --------------------------------------------------*/ - -static const pin_fuse_columns* find_fuse_columns(const pal_data* pal, uint16_t pin) -{ - uint16_t index; - - for (index = 0; index < pal->pinfusecolumnscount; ++index) - { - if (pal->pinfusecolumns[index].pin == pin) - { - return &pal->pinfusecolumns[index]; - } - } - - return nullptr; -} - - - -/*------------------------------------------------- - find_pin_from_fuse_row - finds the pin - associated with a fuse row --------------------------------------------------*/ - -static uint16_t find_pin_from_fuse_row(const pal_data* pal, uint16_t fuserow) -{ - int index; - - for (index = 0; index < pal->pinfuserowscount; ++index) - { - if (pal->pinfuserows[index].fuserowoutputenable != NO_OUTPUT_ENABLE_FUSE_ROW) - { - if (pal->pinfuserows[index].fuserowoutputenable == fuserow) - { - return pal->pinfuserows[index].pin; - } - } - - if (fuserow >= pal->pinfuserows[index].fuserowtermstart && - fuserow <= pal->pinfuserows[index].fuserowtermend) - { - return pal->pinfuserows[index].pin; - } - } - - return 0; -} - - - -/*------------------------------------------------- - calc_fuse_column_count - calculates the total - columns of a pal --------------------------------------------------*/ - -static uint16_t calc_fuse_column_count(const pal_data* pal) -{ - return pal->pinfusecolumnscount * 2; -} - - - -/*------------------------------------------------- - all_fuses_in_row_blown - checks if a fuse row - is all blown --------------------------------------------------*/ - -static int all_fuses_in_row_blown(const pal_data* pal, const jed_data* jed, uint16_t fuserow) -{ - uint16_t columncount = calc_fuse_column_count(pal); - uint16_t column; - - for (column = 0; column < columncount; ++column) - { - if (!jed_get_fuse(jed, fuserow + column)) - { - return 0; - } - } - - return 1; -} - - - -/*------------------------------------------------- - does_output_enable_fuse_row_allow_output - checks - if an output enable fuse row contains a product - term that enables the output. --------------------------------------------------*/ - -static int does_output_enable_fuse_row_allow_output(const pal_data* pal, const jed_data* jed, uint16_t fuserow) -{ - int lowfusestate, highfusestate; - uint16_t index; - - for (index = 0; index < pal->pinfusecolumnscount; ++index) - { - lowfusestate = jed_get_fuse(jed, fuserow + pal->pinfusecolumns[index].lowfusecolumn); - highfusestate = jed_get_fuse(jed, fuserow + pal->pinfusecolumns[index].highfusecolumn); - - if (!lowfusestate && !highfusestate) - { - return 0; - } - } - - return 1; -} - - - -/*------------------------------------------------- - set_input_pins - saves the pins that can be - used by a product term --------------------------------------------------*/ - -static void set_input_pins(const uint16_t* pins, uint16_t pin_count) -{ - uint16_t index; - - for (index = 0; index < pin_count; ++index) - { - inputpins[index] = pins[index]; - - ++inputpinscount; - } -} - - - -/*------------------------------------------------- - set_output_pins - saves the output pins --------------------------------------------------*/ - -static void set_output_pins(const pin_output_config* pin_output_configs, uint16_t pin_count) -{ - uint16_t index; - - for (index = 0; index < pin_count; ++index) - { - outputpins[index].pin = pin_output_configs[index].pin; - outputpins[index].flags = pin_output_configs[index].flags; - - ++outputpinscount; - } -} - - - -/*------------------------------------------------- - is_output_pin - determines if the pin is an - output pin --------------------------------------------------*/ - -static int is_output_pin(uint16_t pin) -{ - uint16_t index; - - for (index = 0; index < outputpinscount; ++index) - { - if (outputpins[index].pin == pin) - { - return 1; - } - } - - return 0; -} - - - -/*------------------------------------------------- - get_pin_output_flags - gets the flags - of an output pin --------------------------------------------------*/ - -static uint16_t get_pin_output_flags(uint16_t pin) -{ - uint16_t index; - - for (index = 0; index < outputpinscount; ++index) - { - if (outputpins[index].pin == pin) - { - return outputpins[index].flags; - } - } - - return 0; -} - - - -/*------------------------------------------------- - get_pin_fuse_state - gets the fuse state of - an input pin --------------------------------------------------*/ - -static uint16_t get_pin_fuse_state(const pal_data* pal, const jed_data* jed, uint16_t pin, uint16_t fuserow) -{ - const pin_fuse_columns* fuse_columns = find_fuse_columns(pal, pin); - int lowfusestate, highfusestate; - - if (!fuse_columns) - { - fprintf(stderr, "Fuse column data missing for pin %d!\n", pin); - - return NO_FUSE_BLOWN; - } - - lowfusestate = jed_get_fuse(jed, fuserow + fuse_columns->lowfusecolumn); - highfusestate = jed_get_fuse(jed, fuserow + fuse_columns->highfusecolumn); - - if (!lowfusestate && highfusestate) - { - return LOW_FUSE_BLOWN; - } - else if (lowfusestate && !highfusestate) - { - return HIGH_FUSE_BLOWN; - } - else if (!lowfusestate && !highfusestate) - { - return NO_FUSE_BLOWN; - } - - return LOWHIGH_FUSE_BLOWN; -} - - - -/*------------------------------------------------- - generate_product_terms - prints the product - terms for a fuse row --------------------------------------------------*/ - -static void generate_product_terms(const pal_data* pal, const jed_data* jed, uint16_t fuserow, char* buffer) -{ - uint16_t index, pin, fuse_state, haveterm, flags; - char tmpbuffer[20]; - - *buffer = 0; - haveterm = 0; - - if (pal->is_product_term_enabled && !pal->is_product_term_enabled(pal, jed, fuserow)) - { - return; - } - - for (index = 0; index < inputpinscount; ++index) - { - pin = inputpins[index]; - - if (pal->get_pin_fuse_state) - { - fuse_state = pal->get_pin_fuse_state(pal, jed, pin, fuserow); - } - else - { - fuse_state = get_pin_fuse_state(pal, jed, pin, fuserow); - } - - if (fuse_state == LOW_FUSE_BLOWN) - { - if (haveterm) - { - strcat(buffer, " " AND_SYMBOL " "); - } - - if (!is_output_pin(pin)) - { - sprintf(tmpbuffer, LOW_SYMBOL INPUT_SYMBOL "%d", pin); - strcat(buffer, tmpbuffer); - } - else - { - flags = get_pin_output_flags(pin); - - if (flags & OUTPUT_FEEDBACK_OUTPUT) - { - if (flags & OUTPUT_COMBINATORIAL) - { - sprintf(tmpbuffer, LOW_SYMBOL OUTPUT_SYMBOL "%d", pin); - } - else if (flags & OUTPUT_REGISTERED) - { - sprintf(tmpbuffer, LOW_SYMBOL REGISTERED_FEEDBACK_OUTPUT_SYMBOL "%d", pin); - } - else - { - tmpbuffer[0] = 0; - - fprintf(stderr, "Unknown output feedback controlled by output enable type for pin %d!\n", pin); - } - } - else if (flags & OUTPUT_FEEDBACK_COMBINATORIAL) - { - sprintf(tmpbuffer, LOW_SYMBOL OUTPUT_FEEDBACK_SYMBOL "%d", pin); - } - else if (flags & OUTPUT_FEEDBACK_REGISTERED) - { - sprintf(tmpbuffer, LOW_SYMBOL REGISTERED_FEEDBACK_SYMBOL "%d", pin); - } - else - { - tmpbuffer[0] = 0; - - fprintf(stderr, "Unknown output feedback type for pin %d!\n", pin); - } - - strcat(buffer, tmpbuffer); - } - - haveterm = 1; - } - - if (fuse_state == HIGH_FUSE_BLOWN) - { - if (haveterm) - { - strcat(buffer, " " AND_SYMBOL " "); - } - - if (!is_output_pin(pin)) - { - sprintf(tmpbuffer, INPUT_SYMBOL "%d", pin); - strcat(buffer, tmpbuffer); - } - else - { - flags = get_pin_output_flags(pin); - - if (flags & OUTPUT_FEEDBACK_OUTPUT) - { - if (flags & OUTPUT_COMBINATORIAL) - { - sprintf(tmpbuffer, OUTPUT_SYMBOL "%d", pin); - } - else if (flags & OUTPUT_REGISTERED) - { - sprintf(tmpbuffer, REGISTERED_FEEDBACK_OUTPUT_SYMBOL "%d", pin); - } - else - { - tmpbuffer[0] = 0; - - fprintf(stderr, "Unknown output feedback controlled by output enable type for pin %d!\n", pin); - } - } - else if (flags & OUTPUT_FEEDBACK_COMBINATORIAL) - { - sprintf(tmpbuffer, OUTPUT_FEEDBACK_SYMBOL "%d", pin); - } - else if (flags & OUTPUT_FEEDBACK_REGISTERED) - { - sprintf(tmpbuffer, REGISTERED_FEEDBACK_SYMBOL "%d", pin); - } - else - { - tmpbuffer[0] = 0; - - fprintf(stderr, "Unknown output feedback type for pin %d!\n", pin); - } - - strcat(buffer, tmpbuffer); - } - - haveterm = 1; - } - } -} - - - -/*------------------------------------------------- - print_input_pins - prints out the input pins --------------------------------------------------*/ - -static void print_input_pins() -{ - uint16_t index; - - printf("Inputs:\n\n"); - - for (index = 0; index < inputpinscount; ++index) - { - printf("%d", inputpins[index]); - - if (index + 1 < inputpinscount) - { - printf(", "); - } - } - - printf("\n\n"); -} - - - -/*------------------------------------------------- - print_output_pins - prints out the output pins --------------------------------------------------*/ - -static void print_output_pins() -{ - uint16_t index, flags; - - printf("Outputs:\n\n"); - - for (index = 0; index < outputpinscount; ++index) - { - flags = outputpins[index].flags; - - printf("%d (", outputpins[index].pin); - - if (flags & OUTPUT_COMBINATORIAL) - { - printf("Combinatorial, "); - } - else if (flags & OUTPUT_REGISTERED) - { - printf("Registered, "); - } - else - { - fprintf(stderr, "Unknown output type for pin %d!\n", outputpins[index].pin); - } - - if (flags & OUTPUT_FEEDBACK_OUTPUT) - { - printf("Output feedback output, "); - } - else if (flags & OUTPUT_FEEDBACK_COMBINATORIAL) - { - printf("Output feedback combinatorial, "); - } - else if (flags & OUTPUT_FEEDBACK_REGISTERED) - { - printf("Output feedback registered, "); - } - else if (flags & OUTPUT_FEEDBACK_NONE) - { - printf("No output feedback, "); - } - else - { - fprintf(stderr, "Unknown output feedback type for pin %d!\n", outputpins[index].pin); - } - - if (flags & OUTPUT_ACTIVELOW) - { - printf("Active low"); - } - else if (flags & OUTPUT_ACTIVEHIGH) - { - printf("Active high"); - } - else - { - fprintf(stderr, "Unknown output state type for pin %d!\n", outputpins[index].pin); - } - - printf(")\n"); - } - - printf("\n"); -} - - - -/*------------------------------------------------- - print_product_terms - prints the product terms - for a pal --------------------------------------------------*/ - -static void print_product_terms(const pal_data* pal, const jed_data* jed) -{ - uint16_t index, columncount, flags, row, haveterms; - char buffer[200]; - int indent, indentindex; - const pin_fuse_rows* fuse_rows; - - columncount = calc_fuse_column_count(pal); - - print_input_pins(); - print_output_pins(); - - printf("Equations:\n\n"); - - for (index = 0; index < outputpinscount; ++index) - { - flags = outputpins[index].flags; - - indent = 0; - - if (flags & OUTPUT_ACTIVELOW) - { - printf(LOW_SYMBOL); - - indent += strlen(LOW_SYMBOL); - } - - if (flags & OUTPUT_COMBINATORIAL) - { - sprintf(buffer, OUTPUT_SYMBOL "%d " COMBINATORIAL_ASSIGNMENT " ", outputpins[index].pin); - } - else if (flags & OUTPUT_REGISTERED) - { - sprintf(buffer, REGISTERED_FEEDBACK_SYMBOL "%d " REGISTERED_ASSIGNMENT " ", outputpins[index].pin); - } - else - { - fprintf(stderr, "Unknown output type for pin %d!\n", outputpins[index].pin); - - continue; - } - - printf("%s", buffer); - - haveterms = 0; - indent += strlen(buffer); - - fuse_rows = find_fuse_rows(pal, outputpins[index].pin); - - if (!fuse_rows) - { - fprintf(stderr, "Fuse row data missing!\n"); - - continue; - } - - for (row = fuse_rows->fuserowtermstart; row <= fuse_rows->fuserowtermend; - row += columncount) - { - generate_product_terms(pal, jed, row, buffer); - - if (strlen(buffer) > 0) - { - if (haveterms) - { - printf(" " OR_SYMBOL "\n"); - - for (indentindex = 0; indentindex < indent; ++indentindex) - { - printf(" "); - } - } - else - { - haveterms = 1; - } - - printf("%s", buffer); - } - } - - printf("\n"); - - /* output enable equations */ - - if (flags & OUTPUT_COMBINATORIAL) - { - printf(OUTPUT_SYMBOL "%d.oe " COMBINATORIAL_ASSIGNMENT " ", outputpins[index].pin); - - if (fuse_rows->fuserowoutputenable == NO_OUTPUT_ENABLE_FUSE_ROW || - all_fuses_in_row_blown(pal, jed, fuse_rows->fuserowoutputenable)) - { - printf("vcc\n"); - } - else - { - generate_product_terms(pal, jed, fuse_rows->fuserowoutputenable, buffer); - - printf("%s\n", buffer); - } - } - else if (flags & OUTPUT_REGISTERED) - { - printf(REGISTERED_FEEDBACK_SYMBOL "%d.oe " COMBINATORIAL_ASSIGNMENT " ", outputpins[index].pin); - - if (fuse_rows->fuserowoutputenable == NO_OUTPUT_ENABLE_FUSE_ROW) - { - printf("OE\n"); - } - else if (all_fuses_in_row_blown(pal, jed, fuse_rows->fuserowoutputenable)) - { - printf("vcc\n"); - } - else - { - generate_product_terms(pal, jed, fuse_rows->fuserowoutputenable, buffer); - - printf("%s\n", buffer); - } - } - - printf("\n"); - } -} - - - -/*------------------------------------------------- - print_pal20xxx_product_terms - prints the product - terms for a PAL20X4, PAL20X8 and PAL20X10 --------------------------------------------------*/ - -static void print_pal20xxx_product_terms(const pal_data* pal, const jed_data* jed) -{ - uint16_t index, columncount, flags, row, haveterms, tmpindex; - char buffer[200]; - int indent, indentindex, rowhasterms[4]; - const pin_fuse_rows* fuse_rows; - - columncount = calc_fuse_column_count(pal); - - print_input_pins(); - print_output_pins(); - - printf("Equations:\n\n"); - - for (index = 0; index < outputpinscount; ++index) - { - flags = outputpins[index].flags; - - indent = 0; - - if (flags & OUTPUT_COMBINATORIAL) - { - sprintf(buffer, LOW_SYMBOL OUTPUT_SYMBOL "%d " COMBINATORIAL_ASSIGNMENT " ", outputpins[index].pin); - - printf("%s", buffer); - - haveterms = 0; - indent += strlen(buffer); - - fuse_rows = find_fuse_rows(pal, outputpins[index].pin); - - for (row = fuse_rows->fuserowtermstart; row <= fuse_rows->fuserowtermend; - row += columncount) - { - generate_product_terms(pal, jed, row, buffer); - - if (strlen(buffer) > 0) - { - if (haveterms) - { - printf(" "); - printf(OR_SYMBOL); - printf("\n"); - - for (indentindex = 0; indentindex < indent; ++indentindex) - { - printf(" "); - } - } - else - { - haveterms = 1; - } - - printf("%s", buffer); - } - } - - printf("\n"); - - /* output enable equation */ - - printf(OUTPUT_SYMBOL "%d.oe " COMBINATORIAL_ASSIGNMENT " ", outputpins[index].pin); - - if (all_fuses_in_row_blown(pal, jed, fuse_rows->fuserowoutputenable)) - { - printf("vcc\n"); - } - else - { - generate_product_terms(pal, jed, fuse_rows->fuserowoutputenable, buffer); - - printf("%s\n", buffer); - } - } - else if (flags & OUTPUT_REGISTERED) - { - sprintf(buffer, LOW_SYMBOL REGISTERED_FEEDBACK_SYMBOL "%d " REGISTERED_ASSIGNMENT " ", outputpins[index].pin); - - printf("%s", buffer); - - haveterms = 0; - indent += strlen(buffer); - - fuse_rows = find_fuse_rows(pal, outputpins[index].pin); - tmpindex = 0; - - memset(rowhasterms, 0, sizeof(rowhasterms)); - - for (row = fuse_rows->fuserowtermstart; row <= fuse_rows->fuserowtermend; - row += columncount) - { - generate_product_terms(pal, jed, row, buffer); - - if (strlen(buffer) > 0) - { - rowhasterms[tmpindex] = 1; - - if (haveterms) - { - if (tmpindex == 1) - { - printf(" " OR_SYMBOL "\n"); - } - else if (tmpindex == 2) - { - printf(" " XOR_SYMBOL "\n"); - } - else if (tmpindex == 3) - { - if (rowhasterms[2]) - { - printf(" " OR_SYMBOL "\n"); - } - else - { - printf(" " XOR_SYMBOL "\n"); - } - } - - for (indentindex = 0; indentindex < indent; ++indentindex) - { - printf(" "); - } - } - else - { - haveterms = 1; - } - - printf("%s", buffer); - } - - ++tmpindex; - } - - printf("\n"); - - /* output enable equation */ - - printf(REGISTERED_FEEDBACK_SYMBOL "%d.oe " COMBINATORIAL_ASSIGNMENT " OE\n", outputpins[index].pin); - } - else - { - fprintf(stderr, "Unknown output type for pin %d!\n", outputpins[index].pin); - } - - printf("\n"); - } -} - - - -/*------------------------------------------------- - print_pal10l8_product_terms - prints the product - terms for a PAL10L8 --------------------------------------------------*/ - -static void print_pal10l8_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal10h8_product_terms - prints the product - terms for a PAL10H8 --------------------------------------------------*/ - -static void print_pal10h8_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal12l6_product_terms - prints the product - terms for a PAL12L6 --------------------------------------------------*/ - -static void print_pal12l6_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal12h6_product_terms - prints the product - terms for a PAL12H6 --------------------------------------------------*/ - -static void print_pal12h6_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal14l4_product_terms - prints the product - terms for a PAL14L4 --------------------------------------------------*/ - -static void print_pal14l4_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal14h4_product_terms - prints the product - terms for a PAL14H4 --------------------------------------------------*/ - -static void print_pal14h4_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal16l2_product_terms - prints the product - terms for a PAL16L2 --------------------------------------------------*/ - -static void print_pal16l2_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal16h2_product_terms - prints the product - terms for a PAL16H2 --------------------------------------------------*/ - -static void print_pal16h2_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal16h2_product_terms - prints the product - terms for a PAL16C1 --------------------------------------------------*/ - -static void print_pal16c1_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal16l8_product_terms - prints the product - terms for a PAL16L8 --------------------------------------------------*/ - -static void print_pal16l8_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal16r4_product_terms - prints the product - terms for a PAL16R4 --------------------------------------------------*/ - -static void print_pal16r4_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal16r6_product_terms - prints the product - terms for a PAL16R6 --------------------------------------------------*/ - -static void print_pal16r6_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal16r8_product_terms - prints the product - terms for a PAL16R8 --------------------------------------------------*/ - -static void print_pal16r8_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 --------------------------------------------------*/ - -static void print_gal16v8_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_peel18cv8_product_terms - prints the product - terms for a PEEL18CV8 --------------------------------------------------*/ - -static void print_peel18cv8_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, 2592, buffer); - - if (strlen(buffer)) - { - printf("Synchronous Preset:\n\n"); - printf("%s\n", buffer); - printf("\n"); - } - - /* Asynchronous Clear */ - - generate_product_terms(pal, jed, 2628, buffer); - - if (strlen(buffer)) - { - printf("Asynchronous Clear:\n\n"); - printf("%s\n", buffer); - printf("\n"); - } -} - - - -/*------------------------------------------------- - print_ampal18p8_product_terms - prints the product - terms for an AMPAL18P8 --------------------------------------------------*/ - -static void print_ampal18p8_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - -/*------------------------------------------------- - print_gal18v10_product_terms - prints the product - terms for a GAL18V10 --------------------------------------------------*/ - -static void print_gal18v10_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, 3420, 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_pal20l8_product_terms - prints the product - terms for a PAL20L8 --------------------------------------------------*/ - -static void print_pal20l8_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal20l10_product_terms - prints the product - terms for a PAL20L10 --------------------------------------------------*/ - -static void print_pal20l10_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal20r4_product_terms - prints the product - terms for a PAL20R4 --------------------------------------------------*/ - -static void print_pal20r4_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal20r6_product_terms - prints the product - terms for a PAL20R6 --------------------------------------------------*/ - -static void print_pal20r6_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal20r8_product_terms - prints the product - terms for a PAL20R8 --------------------------------------------------*/ - -static void print_pal20r8_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- -print_pal20ra10_product_terms - prints the product -terms for a PAL20RA10 --------------------------------------------------*/ - -static void print_pal20ra10_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal20x4_product_terms - prints the product - terms for a PAL20X4 --------------------------------------------------*/ - -static void print_pal20x4_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_pal20xxx_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal20x8_product_terms - prints the product - terms for a PAL20X8 --------------------------------------------------*/ - -static void print_pal20x8_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_pal20xxx_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal20x10_product_terms - prints the product - terms for a PAL20X10 --------------------------------------------------*/ - -static void print_pal20x10_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_pal20xxx_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - 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 --------------------------------------------------*/ - -static void print_82s153_pls153_product_terms(const pal_data* pal, const jed_data* jed) -{ - uint16_t index, columncount, flags, row, haveterms, or_column, fuserow; - char buffer[200]; - int indent, indentindex; - const pin_fuse_rows* fuse_rows; - - columncount = calc_fuse_column_count(pal); - - print_input_pins(); - print_output_pins(); - - printf("Equations:\n\n"); - - for (index = 0; index < outputpinscount; ++index) - { - flags = outputpins[index].flags; - - indent = 0; - - if (flags & OUTPUT_ACTIVELOW) - { - printf(LOW_SYMBOL); - - indent += strlen(LOW_SYMBOL); - } - - sprintf(buffer, OUTPUT_SYMBOL "%d " COMBINATORIAL_ASSIGNMENT " ", outputpins[index].pin); - - printf("%s", buffer); - - haveterms = 0; - indent += strlen(buffer); - - fuse_rows = find_fuse_rows(pal, outputpins[index].pin); - fuserow = 0; - - if (outputpins[index].pin != 9) - { - or_column = 19 - outputpins[index].pin; - } - else - { - or_column = 9; - } - - for (row = 0; row < 32; ++row) - { - if (!jed_get_fuse(jed, fuserow + columncount + or_column)) - { - generate_product_terms(pal, jed, fuserow, buffer); - - if (strlen(buffer) > 0) - { - if (haveterms) - { - printf(" " OR_SYMBOL "\n"); - - for (indentindex = 0; indentindex < indent; ++indentindex) - { - printf(" "); - } - } - else - { - haveterms = 1; - } - - printf("%s", buffer); - } - } - - fuserow += (columncount + 10); - } - - printf("\n"); - - /* output enable equations */ - - printf(OUTPUT_SYMBOL "%d.oe " COMBINATORIAL_ASSIGNMENT " ", outputpins[index].pin); - - if (all_fuses_in_row_blown(pal, jed, fuse_rows->fuserowoutputenable)) - { - printf("vcc\n"); - } - else - { - generate_product_terms(pal, jed, fuse_rows->fuserowoutputenable, buffer); - - printf("%s\n", buffer); - } - - printf("\n"); - } -} - - - -/*------------------------------------------------- - print_ck2605_product_terms - prints the product - terms for a CK2605 --------------------------------------------------*/ - -static void print_ck2605_product_terms(const pal_data* pal, const jed_data* jed) -{ - uint16_t index, columncount, flags, row, haveterms, or_column, fuserow; - char buffer[200]; - int indent, indentindex; - const pin_fuse_rows* fuse_rows; - - columncount = calc_fuse_column_count(pal); - - print_input_pins(); - print_output_pins(); - - printf("Equations:\n\n"); - - for (index = 0; index < outputpinscount; ++index) - { - flags = outputpins[index].flags; - - indent = 0; - - if (flags & OUTPUT_ACTIVELOW) - { - printf(LOW_SYMBOL); - - indent += strlen(LOW_SYMBOL); - } - - sprintf(buffer, OUTPUT_SYMBOL "%d " COMBINATORIAL_ASSIGNMENT " ", outputpins[index].pin); - - printf("%s", buffer); - - haveterms = 0; - indent += strlen(buffer); - - fuse_rows = find_fuse_rows(pal, outputpins[index].pin); - fuserow = 0; - - if (outputpins[index].pin != 9) - { - or_column = 19 - outputpins[index].pin; - } - else - { - or_column = 9; - } - - for (row = 0; row < 16; ++row) - { - if (!jed_get_fuse(jed, fuserow + columncount + or_column)) - { - generate_product_terms(pal, jed, fuserow, buffer); - - if (strlen(buffer) > 0) - { - if (haveterms) - { - printf(" " OR_SYMBOL "\n"); - - for (indentindex = 0; indentindex < indent; ++indentindex) - { - printf(" "); - } - } - else - { - haveterms = 1; - } - - printf("%s", buffer); - } - } - - fuserow += (columncount + 10); - } - - printf("\n"); - - /* output enable equations */ - - printf(OUTPUT_SYMBOL "%d.oe " COMBINATORIAL_ASSIGNMENT " ", outputpins[index].pin); - - if (all_fuses_in_row_blown(pal, jed, fuse_rows->fuserowoutputenable)) - { - printf("vcc\n"); - } - else - { - generate_product_terms(pal, jed, fuse_rows->fuserowoutputenable, buffer); - - printf("%s\n", buffer); - } - - printf("\n"); - } -} - - - -#if defined(ricoh_pals) -/*------------------------------------------------- - print_epl10p8_product_terms - prints the product - terms for a EPL10P8 --------------------------------------------------*/ - -static void print_epl10p8_product_terms(const pal_data* pal, const jed_data* jed) -{ - typedef struct _memory_cell memory_cell; - struct _memory_cell - { - uint16_t pin; - uint16_t or_fuse; /* 0 - intact? */ - uint16_t xor_fuse; /* 0 - intact? */ - }; - - static memory_cell memory_cells[] = { - {12, 661, 662}, - {13, 658, 659}, - {14, 655, 656}, - {15, 652, 653}, - {16, 649, 650}, - {17, 646, 647}, - {18, 643, 644}, - {19, 640, 641}}; - uint16_t index, columncount, flags, haveterms, fuserow; - char buffer[200]; - int indent, row, indentindex; - const pin_fuse_rows* fuse_rows; - - printf("Warning: This is experimental support!\n"); - - columncount = calc_fuse_column_count(pal); - - print_input_pins(); - print_output_pins(); - - printf("Equations:\n\n"); - - for (index = 0; index < std::size(memory_cells); ++index) - { - flags = outputpins[index].flags; - - indent = 0; - - if (flags & OUTPUT_ACTIVELOW) - { - printf(LOW_SYMBOL); - - indent += strlen(LOW_SYMBOL); - } - - sprintf(buffer, OUTPUT_SYMBOL "%d " COMBINATORIAL_ASSIGNMENT " ", outputpins[index].pin); - - printf("%s", buffer); - - haveterms = 0; - indent += strlen(buffer); - - fuse_rows = find_fuse_rows(pal, outputpins[index].pin); - - if (!jed_get_fuse(jed, memory_cells[index].or_fuse) || - !jed_get_fuse(jed, memory_cells[index].xor_fuse)) - { - /* MMI PAL pin compatible configuration */ - - fuserow = fuse_rows->fuserowtermstart; - - for (row = 0; row < 2; ++row) - { - generate_product_terms(pal, jed, fuserow, buffer); - - if (strlen(buffer) > 0) - { - if (haveterms) - { - printf(" " OR_SYMBOL "\n"); - - for (indentindex = 0; indentindex < indent; ++indentindex) - { - printf(" "); - } - } - else - { - haveterms = 1; - } - - printf("%s", buffer); - } - - fuserow += columncount; - } - - printf("\n"); - - printf(OUTPUT_SYMBOL "%d.oe " COMBINATORIAL_ASSIGNMENT " vcc\n", outputpins[index].pin); - - printf("\n"); - } - else if (!jed_get_fuse(jed, memory_cells[index].or_fuse) || - jed_get_fuse(jed, memory_cells[index].xor_fuse)) - { - /* or configuration */ - - fuserow = fuse_rows->fuserowtermstart; - - for (row = 0; row < 4; ++row) - { - generate_product_terms(pal, jed, fuserow, buffer); - - if (strlen(buffer) > 0) - { - if (haveterms) - { - printf(" " OR_SYMBOL "\n"); - - for (indentindex = 0; indentindex < indent; ++indentindex) - { - printf(" "); - } - } - else - { - haveterms = 1; - } - - printf("%s", buffer); - } - - fuse_rows += columncount; - } - - printf("\n"); - - printf(OUTPUT_SYMBOL "%d.oe " COMBINATORIAL_ASSIGNMENT " vcc\n", outputpins[index].pin); - - printf("\n"); - } - else if (jed_get_fuse(jed, memory_cells[index].or_fuse) || - !jed_get_fuse(jed, memory_cells[index].xor_fuse)) - { - /* xor configuration */ - } - else - { - fprintf(stderr, "Unknown fuse configuration for pin %d!", memory_cells[index].pin); - } - } - - printf("Warning: This is experimental support!\n"); -} - - - -/*------------------------------------------------- - print_epl12p6_product_terms - prints the product - terms for a EPL12P6 --------------------------------------------------*/ - -static void print_epl12p6_product_terms(const pal_data* pal, const jed_data* jed) -{ - fprintf(stderr, "Printing product terms not supported for this device!\n"); -} - - - -/*------------------------------------------------- - print_epl14p4_product_terms - prints the product - terms for a EPL14P4 --------------------------------------------------*/ - -static void print_epl14p4_product_terms(const pal_data* pal, const jed_data* jed) -{ - fprintf(stderr, "Printing product terms not supported for this device!\n"); -} - - - -/*------------------------------------------------- - print_epl16p2_product_terms - prints the product - terms for a EPL16P2 --------------------------------------------------*/ - -static void print_epl16p2_product_terms(const pal_data* pal, const jed_data* jed) -{ - fprintf(stderr, "Printing product terms not supported for this device!\n"); -} - - - -/*------------------------------------------------- - print_epl16p8_product_terms - prints the product - terms for a EPL16P8 --------------------------------------------------*/ - -static void print_epl16p8_product_terms(const pal_data* pal, const jed_data* jed) -{ - fprintf(stderr, "Printing product terms not supported for this device!\n"); -} - - - -/*------------------------------------------------- - print_epl16rp8_product_terms - prints the product - terms for a EPL16RP8 --------------------------------------------------*/ - -static void print_epl16rp8_product_terms(const pal_data* pal, const jed_data* jed) -{ - fprintf(stderr, "Printing product terms not supported for this device!\n"); -} - - - -/*------------------------------------------------- - print_epl16rp6_product_terms - prints the product - terms for a EPL16RP6 --------------------------------------------------*/ - -static void print_epl16rp6_product_terms(const pal_data* pal, const jed_data* jed) -{ - fprintf(stderr, "Printing product terms not supported for this device!\n"); -} - - - -/*------------------------------------------------- - print_epl16rp4_product_terms - prints the product - terms for a EPL16RP4 --------------------------------------------------*/ - -static void print_epl16rp4_product_terms(const pal_data* pal, const jed_data* jed) -{ - fprintf(stderr, "Printing product terms not supported for this device!\n"); -} -#endif - - - -/*------------------------------------------------- - print_pal10p8_product_terms - prints the product - terms for a PAL10P8 --------------------------------------------------*/ - -static void print_pal10p8_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_epl12p6_product_terms - prints the product - terms for a PAL12P6 --------------------------------------------------*/ - -static void print_pal12p6_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_epl14p4_product_terms - prints the product - terms for a PAL14P4 --------------------------------------------------*/ - -static void print_pal14p4_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_epl16p2_product_terms - prints the product - terms for a PAL16P2 --------------------------------------------------*/ - -static void print_pal16p2_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal16p8_product_terms - prints the product - terms for a PAL16P8 --------------------------------------------------*/ - -static void print_pal16p8_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal16rp4_product_terms - prints the product - terms for a PAL16RP4 --------------------------------------------------*/ - -static void print_pal16rp4_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal16rp6_product_terms - prints the product - terms for a PAL16RP6 --------------------------------------------------*/ - -static void print_pal16rp6_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal16rp8_product_terms - prints the product - terms for a PAL16RP8 --------------------------------------------------*/ - -static void print_pal16rp8_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal6l16_product_terms - prints the product - terms for a PAL6L16 --------------------------------------------------*/ - -static void print_pal6l16_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal8l14_product_terms - prints the product - terms for a PAL8L14 --------------------------------------------------*/ - -static void print_pal8l14_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal12h10_product_terms - prints the product - terms for a PAL12H10 --------------------------------------------------*/ - -static void print_pal12h10_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal12l10_product_terms - prints the product - terms for a PAL12L10 --------------------------------------------------*/ - -static void print_pal12l10_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal14h8_product_terms - prints the product - terms for a PAL14H8 --------------------------------------------------*/ - -static void print_pal14h8_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal14l8_product_terms - prints the product - terms for a PAL14L8 --------------------------------------------------*/ - -static void print_pal14l8_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal16h6_product_terms - prints the product - terms for a PAL16H6 --------------------------------------------------*/ - -static void print_pal16h6_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal16l6_product_terms - prints the product - terms for a PAL16L6 --------------------------------------------------*/ - -static void print_pal16l6_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal18h4_product_terms - prints the product - terms for a PAL18H4 --------------------------------------------------*/ - -static void print_pal18h4_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal18l4_product_terms - prints the product - terms for a PAL18L4 --------------------------------------------------*/ - -static void print_pal18l4_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal20lc1_product_terms - prints the product - terms for a PAL20LC1 --------------------------------------------------*/ - -static void print_pal20c1_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_pal20l2_product_terms - prints the product - terms for a PAL20L2 --------------------------------------------------*/ - -static void print_pal20l2_product_terms(const pal_data* pal, const jed_data* jed) -{ - print_product_terms(pal, jed); -} - - - -/*------------------------------------------------- - print_82s100_pls100_product_terms - prints the product - terms for a 82S100 and PLS100 --------------------------------------------------*/ - -static void print_82s100_pls100_product_terms(const pal_data* pal, const jed_data* jed) -{ - uint16_t index, columncount, flags, row, haveterms, or_column, fuserow; - char buffer[200]; - int indent, indentindex; - - columncount = calc_fuse_column_count(pal); - - print_input_pins(); - print_output_pins(); - - printf("Equations:\n\n"); - - for (index = 0; index < outputpinscount; ++index) - { - flags = outputpins[index].flags; - - indent = 0; - - if (flags & OUTPUT_ACTIVELOW) - { - printf(LOW_SYMBOL); - - indent += strlen(LOW_SYMBOL); - } - - sprintf(buffer, OUTPUT_SYMBOL "%d " COMBINATORIAL_ASSIGNMENT " ", outputpins[index].pin); - - printf("%s", buffer); - - haveterms = 0; - indent += strlen(buffer); - - fuserow = 0; - - if (outputpins[index].pin >= 15) - { - or_column = 18 - outputpins[index].pin; - } - else - { - or_column = 17 - outputpins[index].pin; - } - - for (row = 0; row < 48; ++row) - { - if (!jed_get_fuse(jed, fuserow + columncount + or_column)) - { - generate_product_terms(pal, jed, fuserow, buffer); - - if (strlen(buffer) > 0) - { - if (haveterms) - { - printf(" " OR_SYMBOL "\n"); - - for (indentindex = 0; indentindex < indent; ++indentindex) - { - printf(" "); - } - } - else - { - haveterms = 1; - } - - printf("%s", buffer); - } - } - - fuserow += (columncount + 8); - } - - printf("\n"); - - /* output enable equations */ - - printf(OUTPUT_SYMBOL "%d.oe " COMBINATORIAL_ASSIGNMENT " ", outputpins[index].pin); - printf("OE\n"); - - printf("\n"); - } -} - - - -/*------------------------------------------------- - config_pal10l8_pins - configures the pins for - a PAL10L8 --------------------------------------------------*/ - -static void config_pal10l8_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11}; - static pin_output_config output_pins[] = { - {12, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {13, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {14, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {15, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {16, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {17, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {18, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {19, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_pal10h8_pins - configures the pins for - a PAL10H8 --------------------------------------------------*/ - -static void config_pal10h8_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11}; - static pin_output_config output_pins[] = { - {12, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {13, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {14, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {15, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {16, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {17, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {18, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {19, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_pal12l6_pins - configures the pins for - a PAL12L6 --------------------------------------------------*/ - -static void config_pal12l6_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 19}; - static pin_output_config output_pins[] = { - {13, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {14, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {15, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {16, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {17, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {18, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_pal12h6_pins - configures the pins for - a PAL12H6 --------------------------------------------------*/ - -static void config_pal12h6_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 19}; - static pin_output_config output_pins[] = { - {13, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {14, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {15, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {16, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {17, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {18, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_pal14l4_pins - configures the pins for - a PAL14L4 --------------------------------------------------*/ - -static void config_pal14l4_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 18, 19}; - static pin_output_config output_pins[] = { - {14, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {15, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {16, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {17, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_pal14h4_pins - configures the pins for - a PAL14H4 --------------------------------------------------*/ - -static void config_pal14h4_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 18, 19}; - static pin_output_config output_pins[] = { - {14, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {15, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {16, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {17, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_pal16l2_pins - configures the pins for - a PAL16L2 --------------------------------------------------*/ - -static void config_pal16l2_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 17, 18, 19}; - static pin_output_config output_pins[] = { - {15, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {16, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_pal16h2_pins - configures the pins for - a PAL16H2 --------------------------------------------------*/ - -static void config_pal16h2_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 17, 18, 19}; - static pin_output_config output_pins[] = { - {15, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {16, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_pal16c1_pins - configures the pins for - a PAL16C1 --------------------------------------------------*/ - -static void config_pal16c1_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 17, 18, 19}; - static pin_output_config output_pins[] = { - {15, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {16, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_pal16l8_pins - configures the pins for - a PAL16L8 --------------------------------------------------*/ - -static void config_pal16l8_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 14, 15, 16, 17, 18}; - pin_output_config output_pins[8]; - uint16_t output_pin_count, index; - - output_pin_count = 0; - - for (index = 0; index < pal->pinfuserowscount; ++index) - { - if (does_output_enable_fuse_row_allow_output(pal, jed, pal->pinfuserows[index].fuserowoutputenable)) - { - output_pins[output_pin_count].pin = pal->pinfuserows[index].pin; - output_pins[output_pin_count].flags = OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; - - ++output_pin_count; - } - } - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, output_pin_count); -} - - - -/*------------------------------------------------- - config_pal16r4_pins - configures the pins for - a PAL16R4 --------------------------------------------------*/ - -static void config_pal16r4_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {2, 3, 4, 5, 6, 7, 8, 9, 12, 13, 14, 15, 16, 17, 18, 19}; - static uint16_t registered_pins[] = {14, 15, 16, 17}; - pin_output_config output_pins[8]; - uint16_t output_pin_count, index; - - output_pin_count = 0; - - if (does_output_enable_fuse_row_allow_output(pal, jed, 1792)) - { - output_pins[output_pin_count].pin = 12; - output_pins[output_pin_count].flags = OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; - - ++output_pin_count; - } - - if (does_output_enable_fuse_row_allow_output(pal, jed, 1536)) - { - output_pins[output_pin_count].pin = 13; - output_pins[output_pin_count].flags = OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; - - ++output_pin_count; - } - - 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; - - ++output_pin_count; - } - - if (does_output_enable_fuse_row_allow_output(pal, jed, 256)) - { - output_pins[output_pin_count].pin = 18; - output_pins[output_pin_count].flags = OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; - - ++output_pin_count; - } - - if (does_output_enable_fuse_row_allow_output(pal, jed, 0)) - { - output_pins[output_pin_count].pin = 19; - output_pins[output_pin_count].flags = OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; - - ++output_pin_count; - } - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, output_pin_count); -} - - - -/*------------------------------------------------- - config_pal16r6_pins - configures the pins - for a PAL16R6 --------------------------------------------------*/ - -static void config_pal16r6_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {2, 3, 4, 5, 6, 7, 8, 9, 12, 13, 14, 15, 16, 17, 18, 19}; - static uint16_t registered_pins[] = {13, 14, 15, 16, 17, 18}; - pin_output_config output_pins[8]; - uint16_t output_pin_count, index; - - output_pin_count = 0; - - if (does_output_enable_fuse_row_allow_output(pal, jed, 1792)) - { - output_pins[output_pin_count].pin = 12; - output_pins[output_pin_count].flags = OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; - - ++output_pin_count; - } - - 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; - - ++output_pin_count; - } - - if (does_output_enable_fuse_row_allow_output(pal, jed, 0)) - { - output_pins[output_pin_count].pin = 19; - output_pins[output_pin_count].flags = OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; - - ++output_pin_count; - } - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, output_pin_count); -} - - - -/*------------------------------------------------- - config_pal16r8_pins - configures the pins for - a PAL16R8 --------------------------------------------------*/ - -static void config_pal16r8_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {2, 3, 4, 5, 6, 7, 8, 9, 12, 13, 14, 15, 16, 17, 18, 19}; - static pin_output_config output_pins[] = { - {12, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {13, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {14, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {15, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {16, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {17, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {18, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {19, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}}; - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_gal16v8_pins - configures the pins for - a GAL16V8 --------------------------------------------------*/ - -static void config_gal16v8_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[] = { - {12, 2055, 2127}, - {13, 2054, 2126}, - {14, 2053, 2125}, - {15, 2052, 2124}, - {16, 2051, 2123}, - {17, 2050, 2122}, - {18, 2049, 2121}, - {19, 2048, 2120}}; - static pin_fuse_rows pinfuserows_registered[] = { - {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_rows pinfuserows_combinatorialcomplex[] = { - {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}}; - 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}, - {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 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}, - {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_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}, - {11, 31, 30}, - {12, 27, 26}, - {13, 23, 22}, - {14, 19, 18}, - {17, 15, 14}, - {18, 11, 10}, - {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}; - 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; - - /* SYN Fuse: 0 - registered, 1 - combinatorial */ - - if (jed_get_fuse(jed, 2192)) - { - /* Combinatorial */ - /* AC0 Fuse: 0 - simple mode, 1 - complex mode */ - - if (jed_get_fuse(jed, 2193)) - { - /* Complex Mode */ - - set_input_pins(input_pins_combinatorialcomplex, std::size(input_pins_combinatorialcomplex)); - - memcpy(gal16v8pinfuserows, pinfuserows_combinatorialcomplex, sizeof(pinfuserows_combinatorialcomplex)); - memcpy(gal16v8pinfusecolumns, pinfusecolumns_combinatorialcomplex, sizeof(pinfusecolumns_combinatorialcomplex)); - - 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)) - { - 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 != 12 && - output_pins[output_pin_count].pin != 19) - { - 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 < 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 < 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 == 15 || macrocells[index].pin == 16) - { - 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 (output_pins[output_pin_count].pin != 15 && - output_pins[output_pin_count].pin != 16) - { - 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; - } - } - - set_input_pins(input_pins_combinatorialsimple, input_pin_count); - } - } - else - { - /* Registered */ - - set_input_pins(input_pins_registered, std::size(input_pins_registered)); - - memcpy(gal16v8pinfusecolumns, pinfusecolumns_registered, sizeof(pinfusecolumns_registered)); - - for (index = 0; index < std::size(macrocells); ++index) - { - if (jed_get_fuse(jed, macrocells[index].ac1_fuse)) - { - /* combinatorial pin */ - - 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)) - { - 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 */ - - gal16v8pinfuserows[index].fuserowoutputenable = pinfuserows_registered[index].fuserowoutputenable; - gal16v8pinfuserows[index].fuserowtermstart = pinfuserows_registered[index].fuserowtermstart; - gal16v8pinfuserows[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_peel18cv8_pins - configures the pins - for a PEEL18CV8 --------------------------------------------------*/ - -static void config_peel18cv8_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 polarity_fuse; /* 0 = active high or 1 = active low */ - uint16_t type_fuse; /* 1 = registered or 0 = combinatorial */ - uint16_t feedback1_fuse; - uint16_t feedback2_fuse; - }; - - static output_logic_macrocell macrocells[] = { - {12, 2692, 2693, 2694, 2695}, - {13, 2688, 2689, 2690, 2691}, - {14, 2684, 2685, 2686, 2687}, - {15, 2680, 2681, 2682, 2683}, - {16, 2676, 2677, 2678, 2679}, - {17, 2672, 2673, 2674, 2675}, - {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[std::size(macrocells)]; - uint16_t index, output_pin_count; - - set_input_pins(input_pins, std::size(input_pins)); - - output_pin_count = 0; - - 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)) - { - /* Combinatorial Feedback (pin is output only) */ - - output_pins[output_pin_count].pin = macrocells[index].pin; - output_pins[output_pin_count].flags = OUTPUT_FEEDBACK_COMBINATORIAL; - - if (jed_get_fuse(jed, macrocells[index].type_fuse)) - { - output_pins[output_pin_count].flags |= OUTPUT_REGISTERED; - } - else - { - output_pins[output_pin_count].flags |= OUTPUT_COMBINATORIAL; - } - - if (jed_get_fuse(jed, macrocells[index].polarity_fuse)) - { - output_pins[output_pin_count].flags |= OUTPUT_ACTIVELOW; - } - else - { - output_pins[output_pin_count].flags |= OUTPUT_ACTIVEHIGH; - } - - ++output_pin_count; - } - else if (!jed_get_fuse(jed, macrocells[index].feedback1_fuse) && - !jed_get_fuse(jed, macrocells[index].feedback2_fuse)) - { - /* Register Feedback (pin is output only) */ - - output_pins[output_pin_count].pin = macrocells[index].pin; - output_pins[output_pin_count].flags = OUTPUT_FEEDBACK_REGISTERED; - - if (jed_get_fuse(jed, macrocells[index].type_fuse)) - { - output_pins[output_pin_count].flags |= OUTPUT_REGISTERED; - } - else - { - output_pins[output_pin_count].flags |= OUTPUT_COMBINATORIAL; - } - - if (jed_get_fuse(jed, macrocells[index].polarity_fuse)) - { - output_pins[output_pin_count].flags |= OUTPUT_ACTIVELOW; - } - else - { - output_pins[output_pin_count].flags |= OUTPUT_ACTIVEHIGH; - } - - ++output_pin_count; - } - else if (jed_get_fuse(jed, macrocells[index].feedback1_fuse) && - jed_get_fuse(jed, macrocells[index].feedback2_fuse)) - { - /* Bi-directional I/O (pin can be input or output) */ - - 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_FEEDBACK_OUTPUT; - - if (jed_get_fuse(jed, macrocells[index].type_fuse)) - { - output_pins[output_pin_count].flags |= OUTPUT_REGISTERED; - } - else - { - output_pins[output_pin_count].flags |= OUTPUT_COMBINATORIAL; - } - - if (jed_get_fuse(jed, macrocells[index].polarity_fuse)) - { - output_pins[output_pin_count].flags |= OUTPUT_ACTIVELOW; - } - else - { - output_pins[output_pin_count].flags |= OUTPUT_ACTIVEHIGH; - } - - ++output_pin_count; - } - } - else if (!jed_get_fuse(jed, macrocells[index].feedback1_fuse) && - jed_get_fuse(jed, macrocells[index].feedback2_fuse)) - { - fprintf(stderr, "Unknown input/feedback select configuration. (Pin %d)\n", - macrocells[index].pin); - - continue; - } - } - - set_output_pins(output_pins, output_pin_count); -} - - - -/*------------------------------------------------- - config_ampal18p8_pins - configures the pins - for an AMPAL18P8 --------------------------------------------------*/ - -static void config_ampal18p8_pins(const pal_data* pal, const jed_data* jed) -{ - 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[8]; - uint16_t index, output_pin_count; - - set_input_pins(input_pins, std::size(input_pins)); - - output_pin_count = 0; - - for (index = 0; index < pal->pinfuserowscount; ++index) - { - if (does_output_enable_fuse_row_allow_output(pal, jed, pal->pinfuserows[index].fuserowoutputenable)) - { - output_pins[output_pin_count].pin = pal->pinfuserows[index].pin; - output_pins[output_pin_count].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; - - if (jed_get_fuse(jed, 2591 + (8 - index))) - { - 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_gal18v10_pins - configures the pins - for a GAL18V10 --------------------------------------------------*/ - -static void config_gal18v10_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[] = { - {9, 3474, 3475}, - {11, 3472, 3473}, - {12, 3470, 3471}, - {13, 3468, 3469}, - {14, 3466, 3467}, - {15, 3464, 3465}, - {16, 3462, 3463}, - {17, 3460, 3461}, - {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[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_pal20l8_pins - configures the pins for - a PAL20L8 --------------------------------------------------*/ - -static void config_pal20l8_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 16, 17, 18, 19, 20, 21, 23}; - pin_output_config output_pins[8]; - uint16_t output_pin_count, index; - - output_pin_count = 0; - - for (index = 0; index < pal->pinfuserowscount; ++index) - { - if (does_output_enable_fuse_row_allow_output(pal, jed, pal->pinfuserows[index].fuserowoutputenable)) - { - output_pins[output_pin_count].pin = pal->pinfuserows[index].pin; - output_pins[output_pin_count].flags = OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL; - - if (pal->pinfuserows[index].pin != 15 && - pal->pinfuserows[index].pin != 22) - { - output_pins[output_pin_count].flags |= OUTPUT_FEEDBACK_OUTPUT; - } - else - { - output_pins[output_pin_count].flags |= OUTPUT_FEEDBACK_NONE; - } - - ++output_pin_count; - } - } - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, output_pin_count); -} - - - -/*------------------------------------------------- - config_pal20l10_pins - configures the pins for - a PAL20L10 --------------------------------------------------*/ - -static void config_pal20l10_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 16, 17, 18, 19, 20, 21, 22}; - pin_output_config output_pins[10]; - uint16_t output_pin_count, index; - - output_pin_count = 0; - - for (index = 0; index < pal->pinfuserowscount; ++index) - { - if (does_output_enable_fuse_row_allow_output(pal, jed, pal->pinfuserows[index].fuserowoutputenable)) - { - output_pins[output_pin_count].pin = pal->pinfuserows[index].pin; - output_pins[output_pin_count].flags = OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL; - - if (pal->pinfuserows[index].pin != 23 && - pal->pinfuserows[index].pin != 14) - { - output_pins[output_pin_count].flags |= OUTPUT_FEEDBACK_OUTPUT; - } - else - { - output_pins[output_pin_count].flags |= OUTPUT_FEEDBACK_NONE; - } - - ++output_pin_count; - } - } - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, output_pin_count); -} - - - -/*------------------------------------------------- - config_pal20r4_pins - configures the pins for - a PAL20R4 --------------------------------------------------*/ - -static void config_pal20r4_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; - static uint16_t registered_pins[] = {17, 18, 19, 20}; - pin_output_config output_pins[8]; - uint16_t output_pin_count, index; - - output_pin_count = 0; - - if (does_output_enable_fuse_row_allow_output(pal, jed, 2240)) - { - output_pins[output_pin_count].pin = 15; - output_pins[output_pin_count].flags = OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; - - ++output_pin_count; - } - - if (does_output_enable_fuse_row_allow_output(pal, jed, 1920)) - { - output_pins[output_pin_count].pin = 16; - output_pins[output_pin_count].flags = OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; - - ++output_pin_count; - } - - 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; - - ++output_pin_count; - } - - if (does_output_enable_fuse_row_allow_output(pal, jed, 320)) - { - output_pins[output_pin_count].pin = 21; - output_pins[output_pin_count].flags = OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; - - ++output_pin_count; - } - - if (does_output_enable_fuse_row_allow_output(pal, jed, 0)) - { - output_pins[output_pin_count].pin = 22; - output_pins[output_pin_count].flags = OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; - - ++output_pin_count; - } - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, output_pin_count); -} - - - -/*------------------------------------------------- - config_pal20r6_pins - configures the pins for - a PAL20R6 --------------------------------------------------*/ - -static void config_pal20r6_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; - static uint16_t registered_pins[] = {16, 17, 18, 19, 20, 21}; - pin_output_config output_pins[8]; - uint16_t output_pin_count, index; - - output_pin_count = 0; - - if (does_output_enable_fuse_row_allow_output(pal, jed, 2240)) - { - output_pins[output_pin_count].pin = 15; - output_pins[output_pin_count].flags = OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; - - ++output_pin_count; - } - - 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; - - ++output_pin_count; - } - - if (does_output_enable_fuse_row_allow_output(pal, jed, 0)) - { - output_pins[output_pin_count].pin = 22; - output_pins[output_pin_count].flags = OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; - - ++output_pin_count; - } - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, output_pin_count); -} - - - -/*------------------------------------------------- - config_pal20r8_pins - configures the pins for - a PAL20R8 --------------------------------------------------*/ - -static void config_pal20r8_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; - static pin_output_config output_pins[] = { - {15, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {16, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {17, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {18, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {19, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {20, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {21, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {22, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}}; - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- -config_pal20ra10_pins - configures the pins for -a PAL20RA10 --------------------------------------------------*/ - -static void config_pal20ra10_pins(const pal_data* pal, const jed_data* jed) -{ - 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 }; - static pin_output_config output_pins[] = { - {14, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {15, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {16, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {17, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {18, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {19, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {20, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {21, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {22, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {23, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}}; - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_pal20x4_pins - configures the pins for - a PAL20X4 --------------------------------------------------*/ - -static void config_pal20x4_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; - static pin_output_config output_pins[] = { - {14, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT}, - {15, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT}, - {16, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT}, - {17, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {18, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {19, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {20, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {21, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT}, - {22, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT}, - {23, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT}}; - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - -/*------------------------------------------------- - config_pal20x8_pins - configures the pins for - a PAL20X8 --------------------------------------------------*/ - -static void config_pal20x8_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; - static pin_output_config output_pins[] = { - {14, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT}, - {15, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {16, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {17, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {18, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {19, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {20, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {21, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {22, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {23, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT}}; - - 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 - a PAL20X10 --------------------------------------------------*/ - -static void config_pal20x10_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; - static pin_output_config output_pins[] = { - {14, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {15, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {16, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {17, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {18, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {19, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {20, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {21, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {22, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {23, OUTPUT_ACTIVELOW | OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}}; - - 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); -} - - - -/*------------------------------------------------- - config_82s153_pls153_pins - configures the pins for - a 82S153/PLS153 --------------------------------------------------*/ - -static void config_82s153_pls153_pins(const pal_data* pal, const jed_data* jed) -{ - 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[10]; - uint16_t output_pin_count, index; - - output_pin_count = 0; - - for (index = 0; index < pal->pinfuserowscount; ++index) - { - if (does_output_enable_fuse_row_allow_output(pal, jed, pal->pinfuserows[index].fuserowoutputenable)) - { - output_pins[output_pin_count].pin = pal->pinfuserows[index].pin; - output_pins[output_pin_count].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; - - if (jed_get_fuse(jed, 1832 + (9 - index))) - { - 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_ck2605_pins - configures the pins for - a CK2605 --------------------------------------------------*/ - -static void config_ck2605_pins(const pal_data* pal, const jed_data* jed) -{ - 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[10]; - uint16_t output_pin_count, index; - - output_pin_count = 0; - - for (index = 0; index < pal->pinfuserowscount; ++index) - { - if (does_output_enable_fuse_row_allow_output(pal, jed, pal->pinfuserows[index].fuserowoutputenable)) - { - output_pins[output_pin_count].pin = pal->pinfuserows[index].pin; - output_pins[output_pin_count].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; - - if (jed_get_fuse(jed, 1096 + (9 - index))) - { - 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); -} - - - -#if defined(ricoh_pals) -/*------------------------------------------------- - config_epl10p8_pins - configures the pins for - a EPL10P8 --------------------------------------------------*/ - -static void config_epl10p8_pins(const pal_data* pal, const jed_data* jed) -{ - typedef struct _memory_cell memory_cell; - struct _memory_cell - { - uint16_t pin; - uint16_t polarity_fuse; /* 0 - active low?, 1 - active high? */ - }; - - static memory_cell memory_cells[] = { - {12, 663}, - {13, 660}, - {14, 657}, - {15, 654}, - {16, 651}, - {17, 648}, - {18, 645}, - {19, 642}}; - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11}; - pin_output_config output_pins[8]; - uint16_t 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; - - if (!jed_get_fuse(jed, memory_cells[index].polarity_fuse)) - { - output_pins[index].flags |= OUTPUT_ACTIVELOW; - } - else - { - output_pins[index].flags |= OUTPUT_ACTIVEHIGH; - } - } - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_epl12p6_pins - configures the pins for - a EPL12P6 --------------------------------------------------*/ - -static void config_epl12p6_pins(const pal_data* pal, const jed_data* jed) -{ - typedef struct _memory_cell memory_cell; - struct _memory_cell - { - uint16_t pin; - uint16_t polarity_fuse; /* 0 - active low?, 1 - active high? */ - uint16_t or_fuse; /* 0 - intact? */ - uint16_t xor_fuse; /* 0 - intact? */ - }; - - static memory_cell memory_cells[] = { - {13, 785, 783, 784}, - {14, 782, 780, 781}, - {15, 779, 777, 778}, - {16, 776, 774, 775}, - {17, 773, 771, 772}, - {18, 770, 768, 769}}; - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 19}; - pin_output_config output_pins[8]; - uint16_t 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; - - if (!jed_get_fuse(jed, memory_cells[index].polarity_fuse)) - { - output_pins[index].flags |= OUTPUT_ACTIVELOW; - } - else - { - output_pins[index].flags |= OUTPUT_ACTIVEHIGH; - } - } - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_epl14p4_pins - configures the pins for - a EPL14P4 --------------------------------------------------*/ - -static void config_epl14p4_pins(const pal_data* pal, const jed_data* jed) -{ - typedef struct _memory_cell memory_cell; - struct _memory_cell - { - uint16_t pin; - uint16_t polarity_fuse; /* 0 - active low?, 1 - active high? */ - uint16_t or_fuse; /* 0 - intact? */ - uint16_t xor_fuse; /* 0 - intact? */ - }; - - static memory_cell memory_cells[] = { - {14, 907, 905, 906}, - {15, 904, 902, 903}, - {16, 901, 899, 900}, - {17, 898, 896, 897}}; - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 18, 19}; - pin_output_config output_pins[8]; - uint16_t 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; - - if (!jed_get_fuse(jed, memory_cells[index].polarity_fuse)) - { - output_pins[index].flags |= OUTPUT_ACTIVELOW; - } - else - { - output_pins[index].flags |= OUTPUT_ACTIVEHIGH; - } - } - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_epl16p2_pins - configures the pins for - a EPL16P2 --------------------------------------------------*/ - -static void config_epl16p2_pins(const pal_data* pal, const jed_data* jed) -{ - typedef struct _memory_cell memory_cell; - struct _memory_cell - { - uint16_t pin; - uint16_t polarity_fuse; /* 0 - active low?, 1 - active high? */ - uint16_t or_fuse; /* 0 - intact? */ - uint16_t xor_fuse; /* 0 - intact? */ - }; - - static memory_cell memory_cells[] = { - {15, 1029, 1027, 1028}, - {16, 1026, 1024, 1025}}; - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 17, 18, 19}; - pin_output_config output_pins[8]; - uint16_t 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; - - if (!jed_get_fuse(jed, memory_cells[index].polarity_fuse)) - { - output_pins[index].flags |= OUTPUT_ACTIVELOW; - } - else - { - output_pins[index].flags |= OUTPUT_ACTIVEHIGH; - } - } - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_epl16p8_pins - configures the pins for - a EPL16P8 --------------------------------------------------*/ - -static void config_epl16p8_pins(const pal_data* pal, const jed_data* jed) -{ - typedef struct _memory_cell memory_cell; - struct _memory_cell - { - uint16_t pin; - uint16_t polarity_fuse; /* 0 - active low?, 1 - active high? */ - uint16_t or_fuse; /* 0 - intact? */ - uint16_t xor_fuse; /* 0 - intact? */ - }; - - static memory_cell memory_cells[] = { - {12, 2071, 2069, 2070}, - {13, 2068, 2066, 2067}, - {14, 2065, 2063, 2064}, - {15, 2062, 2060, 2061}, - {16, 2059, 2057, 2058}, - {17, 2056, 2054, 2055}, - {18, 2053, 2051, 2052}, - {19, 2050, 2048, 2049}}; - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11}; - pin_output_config output_pins[8]; - uint16_t 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; - - if (!jed_get_fuse(jed, memory_cells[index].polarity_fuse)) - { - output_pins[index].flags |= OUTPUT_ACTIVELOW; - } - else - { - output_pins[index].flags |= OUTPUT_ACTIVEHIGH; - } - } - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_epl16rp8_pins - configures the pins for - a EPL16RP8 --------------------------------------------------*/ - -static void config_epl16rp8_pins(const pal_data* pal, const jed_data* jed) -{ - typedef struct _memory_cell memory_cell; - struct _memory_cell - { - uint16_t pin; - uint16_t polarity_fuse; /* 0 - active low?, 1 - active high? */ - uint16_t or_fuse; /* 0 - intact? */ - uint16_t xor_fuse; /* 0 - intact? */ - }; - - static memory_cell memory_cells[] = { - {12, 2071, 2069, 2070}, - {13, 2068, 2066, 2067}, - {14, 2065, 2063, 2064}, - {15, 2062, 2060, 2061}, - {16, 2059, 2057, 2058}, - {17, 2056, 2054, 2055}, - {18, 2053, 2051, 2052}, - {19, 2050, 2048, 2049}}; - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11}; - pin_output_config output_pins[8]; - uint16_t 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; - - if (!jed_get_fuse(jed, memory_cells[index].polarity_fuse)) - { - output_pins[index].flags |= OUTPUT_ACTIVELOW; - } - else - { - output_pins[index].flags |= OUTPUT_ACTIVEHIGH; - } - } - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_epl16rp6_pins - configures the pins for - a EPL16RP6 --------------------------------------------------*/ - -static void config_epl16rp6_pins(const pal_data* pal, const jed_data* jed) -{ - typedef struct _memory_cell memory_cell; - struct _memory_cell - { - uint16_t pin; - uint16_t polarity_fuse; /* 0 - active low?, 1 - active high? */ - uint16_t or_fuse; /* 0 - intact? */ - uint16_t xor_fuse; /* 0 - intact? */ - }; - - static memory_cell memory_cells[] = { - {12, 2071, 2069, 2070}, - {13, 2068, 2066, 2067}, - {14, 2065, 2063, 2064}, - {15, 2062, 2060, 2061}, - {16, 2059, 2057, 2058}, - {17, 2056, 2054, 2055}, - {18, 2053, 2051, 2052}, - {19, 2050, 2048, 2049}}; - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11}; - pin_output_config output_pins[8]; - uint16_t index; - - for (index = 0; index < std::size(memory_cells); ++index) - { - output_pins[index].pin = memory_cells[index].pin; - - if (memory_cells[index].pin == 13 || memory_cells[index].pin == 14 || - memory_cells[index].pin == 15 || memory_cells[index].pin == 16 || - memory_cells[index].pin == 17 || memory_cells[index].pin == 18) - { - output_pins[index].flags = OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED; - } - else - { - output_pins[index].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; - } - - if (!jed_get_fuse(jed, memory_cells[index].polarity_fuse)) - { - output_pins[index].flags |= OUTPUT_ACTIVELOW; - } - else - { - output_pins[index].flags |= OUTPUT_ACTIVEHIGH; - } - } - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_epl16rp4_pins - configures the pins for - a EPL16RP4 --------------------------------------------------*/ - -static void config_epl16rp4_pins(const pal_data* pal, const jed_data* jed) -{ - typedef struct _memory_cell memory_cell; - struct _memory_cell - { - uint16_t pin; - uint16_t polarity_fuse; /* 0 - active low?, 1 - active high? */ - uint16_t or_fuse; /* 0 - intact? */ - uint16_t xor_fuse; /* 0 - intact? */ - }; - - static memory_cell memory_cells[] = { - {12, 2071, 2069, 2070}, - {13, 2068, 2066, 2067}, - {14, 2065, 2063, 2064}, - {15, 2062, 2060, 2061}, - {16, 2059, 2057, 2058}, - {17, 2056, 2054, 2055}, - {18, 2053, 2051, 2052}, - {19, 2050, 2048, 2049}}; - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11}; - pin_output_config output_pins[8]; - uint16_t index; - - for (index = 0; index < std::size(memory_cells); ++index) - { - output_pins[index].pin = memory_cells[index].pin; - - if (memory_cells[index].pin == 14 || memory_cells[index].pin == 15 || - memory_cells[index].pin == 16 || memory_cells[index].pin == 17) - { - output_pins[index].flags = OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED; - } - else - { - output_pins[index].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; - } - - if (!jed_get_fuse(jed, memory_cells[index].polarity_fuse)) - { - output_pins[index].flags |= OUTPUT_ACTIVELOW; - } - else - { - output_pins[index].flags |= OUTPUT_ACTIVEHIGH; - } - } - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} -#endif - - - -/*------------------------------------------------- - config_pal10p8_pins - configures the pins for - a PAL10P8 --------------------------------------------------*/ - -static void config_pal10p8_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11}; - pin_output_config output_pins[8]; - uint16_t 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; - - if (!jed_get_fuse(jed, 327 - index)) - { - output_pins[index].flags |= OUTPUT_ACTIVELOW; - } - else - { - output_pins[index].flags |= OUTPUT_ACTIVEHIGH; - } - } - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_pal12p6_pins - configures the pins for - a PAL12P6A --------------------------------------------------*/ - -static void config_pal12p6_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 19}; - pin_output_config output_pins[6]; - uint16_t 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; - - if (!jed_get_fuse(jed, 389 - index)) - { - output_pins[index].flags |= OUTPUT_ACTIVELOW; - } - else - { - output_pins[index].flags |= OUTPUT_ACTIVEHIGH; - } - } - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_pal14p4_pins - configures the pins for - a PAL14P4 --------------------------------------------------*/ - -static void config_pal14p4_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 18, 19}; - pin_output_config output_pins[4]; - uint16_t 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; - - if (!jed_get_fuse(jed, 451 - index)) - { - output_pins[index].flags |= OUTPUT_ACTIVELOW; - } - else - { - output_pins[index].flags |= OUTPUT_ACTIVEHIGH; - } - } - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_pal16p2_pins - configures the pins for - a PAL16P2 --------------------------------------------------*/ - -static void config_pal16p2_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 17, 18, 19}; - pin_output_config output_pins[2]; - uint16_t 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; - - if (!jed_get_fuse(jed, 513 - index)) - { - output_pins[index].flags |= OUTPUT_ACTIVELOW; - } - else - { - output_pins[index].flags |= OUTPUT_ACTIVEHIGH; - } - } - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_pal16p8_pins - configures the pins for - a PAL16P8 --------------------------------------------------*/ - -static void config_pal16p8_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 14, 15, 16, 17, 18}; - pin_output_config output_pins[8]; - uint16_t output_pin_count, index; - - output_pin_count = 0; - - for (index = 0; index < pal->pinfuserowscount; ++index) - { - if (does_output_enable_fuse_row_allow_output(pal, jed, pal->pinfuserows[index].fuserowoutputenable)) - { - output_pins[output_pin_count].pin = pal->pinfuserows[index].pin; - output_pins[output_pin_count].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; - - if (!jed_get_fuse(jed, 2055 - index)) - { - 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_pal16rp4_pins - configures the pins for - a PAL16RP4 --------------------------------------------------*/ - -static void config_pal16rp4_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {2, 3, 4, 5, 6, 7, 8, 9, 12, 13, 14, 15, 16, 17, 18, 19}; - static uint16_t registered_pins[] = {14, 15, 16, 17}; - pin_output_config output_pins[8]; - uint16_t output_pin_count, index; - - output_pin_count = 0; - - if (does_output_enable_fuse_row_allow_output(pal, jed, 1792)) - { - output_pins[output_pin_count].pin = 12; - output_pins[output_pin_count].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; - - if (!jed_get_fuse(jed, 2055)) - { - output_pins[output_pin_count].flags |= OUTPUT_ACTIVELOW; - } - else - { - output_pins[output_pin_count].flags |= OUTPUT_ACTIVEHIGH; - } - - ++output_pin_count; - } - - if (does_output_enable_fuse_row_allow_output(pal, jed, 1536)) - { - output_pins[output_pin_count].pin = 13; - output_pins[output_pin_count].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; - - if (!jed_get_fuse(jed, 2054)) - { - output_pins[output_pin_count].flags |= OUTPUT_ACTIVELOW; - } - else - { - output_pins[output_pin_count].flags |= OUTPUT_ACTIVEHIGH; - } - - ++output_pin_count; - } - - 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; - - if (!jed_get_fuse(jed, 2053 - index)) - { - output_pins[output_pin_count].flags |= OUTPUT_ACTIVELOW; - } - else - { - output_pins[output_pin_count].flags |= OUTPUT_ACTIVEHIGH; - } - - ++output_pin_count; - } - - if (does_output_enable_fuse_row_allow_output(pal, jed, 256)) - { - output_pins[output_pin_count].pin = 18; - output_pins[output_pin_count].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; - - if (!jed_get_fuse(jed, 2049)) - { - output_pins[output_pin_count].flags |= OUTPUT_ACTIVELOW; - } - else - { - output_pins[output_pin_count].flags |= OUTPUT_ACTIVEHIGH; - } - - ++output_pin_count; - } - - if (does_output_enable_fuse_row_allow_output(pal, jed, 0)) - { - output_pins[output_pin_count].pin = 19; - output_pins[output_pin_count].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; - - if (!jed_get_fuse(jed, 2048)) - { - 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_pal16rp6_pins - configures the pins for - a PAL16RP6 --------------------------------------------------*/ - -static void config_pal16rp6_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {2, 3, 4, 5, 6, 7, 8, 9, 12, 13, 14, 15, 16, 17, 18, 19}; - static uint16_t registered_pins[] = {13, 14, 15, 16, 17, 18}; - pin_output_config output_pins[8]; - uint16_t output_pin_count, index; - - output_pin_count = 0; - - if (does_output_enable_fuse_row_allow_output(pal, jed, 1792)) - { - output_pins[output_pin_count].pin = 12; - output_pins[output_pin_count].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; - - if (!jed_get_fuse(jed, 2055)) - { - output_pins[output_pin_count].flags |= OUTPUT_ACTIVELOW; - } - else - { - output_pins[output_pin_count].flags |= OUTPUT_ACTIVEHIGH; - } - - ++output_pin_count; - } - - 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; - - if (!jed_get_fuse(jed, 2054 - index)) - { - output_pins[output_pin_count].flags |= OUTPUT_ACTIVELOW; - } - else - { - output_pins[output_pin_count].flags |= OUTPUT_ACTIVEHIGH; - } - - ++output_pin_count; - } - - if (does_output_enable_fuse_row_allow_output(pal, jed, 0)) - { - output_pins[output_pin_count].pin = 19; - output_pins[output_pin_count].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_OUTPUT; - - if (!jed_get_fuse(jed, 2048)) - { - 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_pal16rp8_pins - configures the pins for - a PAL16RP8 --------------------------------------------------*/ - -static void config_pal16rp8_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {2, 3, 4, 5, 6, 7, 8, 9, 12, 13, 14, 15, 16, 17, 18, 19}; - pin_output_config output_pins[] = { - {12, OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {13, OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {14, OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {15, OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {16, OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {17, OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {18, OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}, - {19, OUTPUT_REGISTERED | OUTPUT_FEEDBACK_REGISTERED}}; - uint16_t index; - - for (index = 0; index < std::size(output_pins); ++index) - { - if (!jed_get_fuse(jed, 2055 - index)) - { - output_pins[index].flags |= OUTPUT_ACTIVELOW; - } - else - { - output_pins[index].flags |= OUTPUT_ACTIVEHIGH; - } - } - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_pal6l16_pins - configures the pins for - a PAL6L16 --------------------------------------------------*/ - -static void config_pal6l16_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {4, 5, 6, 7, 8, 9}; - static pin_output_config output_pins[] = { - {1, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {2, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {3, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {10, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {11, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {13, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {14, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {15, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {16, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {17, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {18, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {19, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {20, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {21, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {22, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {23, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_pal8l14_pins - configures the pins for - a PAL8L14 --------------------------------------------------*/ - -static void config_pal8l14_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {3, 4, 5, 6, 7, 8, 9, 10}; - static pin_output_config output_pins[] = { - {1, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {2, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {11, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {13, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {14, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {15, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {16, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {17, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {18, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {19, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {20, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {21, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {22, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {23, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_pal12h10_pins - configures the pins for - a PAL12H10 --------------------------------------------------*/ - -static void config_pal12h10_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13}; - static pin_output_config output_pins[] = { - {14, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {15, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {16, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {17, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {18, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {19, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {20, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {21, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {22, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {23, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_pal12l10_pins - configures the pins for - a PAL12L10 --------------------------------------------------*/ - -static void config_pal12l10_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13}; - static pin_output_config output_pins[] = { - {14, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {15, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {16, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {17, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {18, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {19, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {20, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {21, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {22, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {23, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_pal14h8_pins - configures the pins for - a PAL14H8 --------------------------------------------------*/ - -static void config_pal14h8_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 23}; - static pin_output_config output_pins[] = { - {15, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {16, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {17, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {18, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {19, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {20, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {21, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {22, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_pal14l8_pins - configures the pins for - a PAL14L8 --------------------------------------------------*/ - -static void config_pal14l8_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 23}; - static pin_output_config output_pins[] = { - {15, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {16, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {17, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {18, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {19, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {20, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {21, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {22, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_pal16h6_pins - configures the pins for - a PAL16H6 --------------------------------------------------*/ - -static void config_pal16h6_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 22, 23}; - static pin_output_config output_pins[] = { - {16, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {17, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {18, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {19, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {20, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {21, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_pal16l6_pins - configures the pins for - a PAL16L6 --------------------------------------------------*/ - -static void config_pal16l6_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 22, 23}; - static pin_output_config output_pins[] = { - {16, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {17, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {18, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {19, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {20, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {21, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_pal18h4_pins - configures the pins for - a PAL18H4 --------------------------------------------------*/ - -static void config_pal18h4_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 21, 22, 23}; - static pin_output_config output_pins[] = { - {17, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {18, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {19, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {20, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_pal18l4_pins - configures the pins for - a PAL18L4 --------------------------------------------------*/ - -static void config_pal18l4_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 21, 22, 23}; - static pin_output_config output_pins[] = { - {17, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {18, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {19, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {20, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_pal20c1_pins - configures the pins for - a PAL20C1 --------------------------------------------------*/ - -static void config_pal20c1_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 20, 21, 22, 23}; - static pin_output_config output_pins[] = { - {18, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {19, OUTPUT_ACTIVEHIGH | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_pal20l2_pins - configures the pins for - a PAL20L2 --------------------------------------------------*/ - -static void config_pal20l2_pins(const pal_data* pal, const jed_data* jed) -{ - static uint16_t input_pins[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 20, 21, 22, 23}; - static pin_output_config output_pins[] = { - {18, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}, - {19, OUTPUT_ACTIVELOW | OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE}}; - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - config_82s100_pls100_pins - configures the pins for - a 82S100 and PLS100 --------------------------------------------------*/ - -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 < std::size(output_pins); ++index) - { - output_pins[index].pin = pal->pinfuserows[index].pin; - output_pins[index].flags = OUTPUT_COMBINATORIAL | OUTPUT_FEEDBACK_NONE; - - if (jed_get_fuse(jed, 1920 + index)) - { - output_pins[index].flags |= OUTPUT_ACTIVELOW; - } - else - { - output_pins[index].flags |= OUTPUT_ACTIVEHIGH; - } - } - - set_input_pins(input_pins, std::size(input_pins)); - set_output_pins(output_pins, std::size(output_pins)); -} - - - -/*------------------------------------------------- - is_gal16v8_product_term_enabled - determines if - a fuse row in a GAL16V8 is enabled --------------------------------------------------*/ - -static int is_gal16v8_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)) + 2128; - - if (fuse_ptd > 2191) - { - fprintf(stderr, "Fuse row %d is illegal!\n", fuserow); - - return 0; - } - - return jed_get_fuse(jed, fuse_ptd); -} - - - -/*------------------------------------------------- - 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 --------------------------------------------------*/ - -static uint16_t get_peel18cv8_pin_fuse_state(const pal_data* pal, const jed_data* jed, uint16_t pin, uint16_t fuserow) -{ - const pin_fuse_columns* fuse_columns; - int lowfusestate, highfusestate, tmpfusestate, swapfusestates; - uint16_t cfgpin; - - /* Synchronous Preset or Asynchronous Clear fuse row? */ - - if (fuserow == 2592 || fuserow == 2628) - { - return get_pin_fuse_state(pal, jed, pin, fuserow); - } - - fuse_columns = find_fuse_columns(pal, pin); - - if (!fuse_columns) - { - fprintf(stderr, "Fuse column data missing for pin %d!\n", pin); - - return NO_FUSE_BLOWN; - } - - cfgpin = find_pin_from_fuse_row(pal, fuserow); - - if (!cfgpin) - { - fprintf(stderr, "Pin from fuse row failed! (Fuse row: %d)\n", fuserow); - - return get_pin_fuse_state(pal, jed, pin, fuserow); - } - - lowfusestate = jed_get_fuse(jed, fuserow + fuse_columns->lowfusecolumn); - highfusestate = jed_get_fuse(jed, fuserow + fuse_columns->highfusecolumn); - swapfusestates = 0; - - if (is_output_pin(pin) && is_output_pin(cfgpin)) - { - if (get_pin_output_flags(cfgpin) & OUTPUT_FEEDBACK_COMBINATORIAL) - { - if ((get_pin_output_flags(pin) & OUTPUT_ACTIVELOW) && - (get_pin_output_flags(pin) & OUTPUT_FEEDBACK_COMBINATORIAL)) - { - swapfusestates = 1; - } - } - else if (get_pin_output_flags(cfgpin) & OUTPUT_FEEDBACK_REGISTERED) - { - if ((get_pin_output_flags(pin) & OUTPUT_ACTIVELOW) && - (get_pin_output_flags(pin) & OUTPUT_FEEDBACK_REGISTERED)) - { - swapfusestates = 1; - } - } - else if (get_pin_output_flags(cfgpin) & OUTPUT_FEEDBACK_OUTPUT) - { - if ((get_pin_output_flags(pin) & OUTPUT_ACTIVELOW) && - (get_pin_output_flags(pin) & OUTPUT_FEEDBACK_REGISTERED)) - { - swapfusestates = 1; - } - } - else - { - fprintf(stderr, "Unknown output pin type! (Fuse row: %d)\n", fuserow); - } - } - - if (swapfusestates) - { - tmpfusestate = lowfusestate; - lowfusestate = highfusestate; - highfusestate = tmpfusestate; - } - - if (!lowfusestate && highfusestate) - { - return LOW_FUSE_BLOWN; - } - else if (lowfusestate && !highfusestate) - { - return HIGH_FUSE_BLOWN; - } - else if (!lowfusestate && !highfusestate) - { - return NO_FUSE_BLOWN; - } - - return LOWHIGH_FUSE_BLOWN; -} - - - -/*------------------------------------------------- - write_dest_file - write a memory buffer raw - into a desintation file --------------------------------------------------*/ - -static int write_dest_file(const char *dstfile) -{ - size_t bytes; - FILE *file; - - /* open the source file */ - file = fopen(dstfile, "wb"); - if (!file) - { - fprintf(stderr, "Unable to open target file '%s'!\n", dstfile); - return 1; - } - - /* write the data */ - bytes = fwrite(dstbuf, 1, dstbuflen, file); - if (bytes != dstbuflen) - { - fprintf(stderr, "Error writing %d bytes to the target!\n", (int)dstbuflen); - fclose(file); - return 1; - } - - /* close up shop */ - fclose(file); - return 0; -} - - - -/*------------------------------------------------- - print_usage - prints out the supported command - line arguments --------------------------------------------------*/ - -static int print_usage() -{ - fprintf(stderr, - "Usage:\n" - " jedutil -convert [fuses] -- convert JEDEC to binary form\n" - " jedutil -convert [fuses] -- convert Berkeley standard PLA to binary form\n" - " jedutil -convert -- convert binary to JEDEC form\n" - " jedutil -view -- dump JED logic equations\n" - " jedutil -view -- dump binary logic equations\n" - " jedutil -viewlist -- view list of supported devices\n" - " jedutil -listcompatible -- list compatible devices\n" - " jedutil -listcompatible -- list compatible devices\n" - ); - - return 0; -} - - - -/*------------------------------------------------- - command_convert - convert files --------------------------------------------------*/ - -static int command_convert(int argc, char *argv[]) -{ - const char *srcfile, *dstfile; - int src_is_jed, src_is_pla, dst_is_jed; - int numfuses = 0; - jed_data jed; - - if (argc < 2) - { - return print_usage(); - } - - /* extract arguments */ - srcfile = argv[0]; - dstfile = argv[1]; - if (argc >= 3) - numfuses = atoi(argv[2]); - - /* does the source end in '.jed'? */ - src_is_jed = is_jed_file(srcfile); - - /* does the source end in '.pla'? */ - src_is_pla = is_pla_file(srcfile); - - /* does the destination end in '.jed'? */ - dst_is_jed = is_jed_file(dstfile); - - /* error if neither or both are .jed */ - if (!src_is_jed && !src_is_pla && !dst_is_jed) - { - fprintf(stderr, "At least one of the filenames must end in .jed or .pla!\n"); - return 1; - } - if (src_is_jed && dst_is_jed) - { - fprintf(stderr, "Both filenames cannot end in .jed!\n"); - return 1; - } - - /* read the source file */ - auto src = util::stdio_read(fopen(srcfile, "rb")); - if (!src) - { - fprintf(stderr, "Unable to open source file '%s'!\n", srcfile); - return 1; - } - - memset(&jed, 0, sizeof(jed)); - - /* if the source is JED or PLA, convert to binary */ - if (src_is_jed || src_is_pla) - { - printf("Converting '%s' to binary form '%s'\n", srcfile, dstfile); - - /* read the fuse data */ - int err; - if (src_is_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"); 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 */ - if (numfuses != 0) - jed.numfuses = numfuses; - - /* print out data */ - printf("Source file read successfully\n"); - printf(" Total fuses = %d\n", jed.numfuses); - - /* generate the output */ - dstbuflen = jedbin_output(&jed, nullptr, 0); - dstbuf = (uint8_t *)malloc(dstbuflen); - if (!dstbuf) - { - fprintf(stderr, "Unable to allocate %d bytes for the target buffer!\n", (int)dstbuflen); - return 1; - } - dstbuflen = jedbin_output(&jed, dstbuf, dstbuflen); - } - - /* if the source is binary, convert to JED */ - else - { - printf("Converting '%s' to JED form '%s'\n", srcfile, dstfile); - - /* read the binary data */ - int err = jedbin_parse(*src, &jed); - src.reset(); - - switch (err) - { - case JEDERR_INVALID_DATA: fprintf(stderr, "Fatal error: Invalid binary JEDEC file\n"); return 1; - } - - /* print out data */ - printf("Source file read successfully\n"); - printf(" Total fuses = %d\n", jed.numfuses); - - /* generate the output */ - dstbuflen = jed_output(&jed, nullptr, 0); - dstbuf = (uint8_t *)malloc(dstbuflen); - if (!dstbuf) - { - fprintf(stderr, "Unable to allocate %d bytes for the target buffer!\n", (int)dstbuflen); - return 1; - } - dstbuflen = jed_output(&jed, dstbuf, dstbuflen); - } - - /* write the destination file */ - int err = write_dest_file(dstfile); - if (err != 0) - return 1; - - printf("Target file written successfully\n"); - - return 0; -} - - - -/*------------------------------------------------- - command_view - views the contents of a file --------------------------------------------------*/ - -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; - - if (argc < 2) - { - return print_usage(); - } - - /* extract arguments */ - srcfile = argv[0]; - palname = argv[1]; - - /* does the source end in '.jed'? */ - is_jed = is_jed_file(srcfile); - - /* find the pal entry */ - 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 */ - 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; - } - } - - 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; - goto end; - } - - /* generate equations from fuse map */ - - pal->config_pins(pal, &jed); - - if (pal->print_product_terms) - { - pal->print_product_terms(pal, &jed); - } - else - { - fprintf(stderr, "Viewing product terms not supported for this pal type."); - result = 1; - } - -end: - return result; -} - - - -/*------------------------------------------------- - command_viewlist - views the list of supported - jeds --------------------------------------------------*/ - -static int command_viewlist(int argc, char *argv[]) -{ - typedef std::set string_set; - - string_set nameset; - int index; - - if (argc > 0) - { - return print_usage(); - } - - 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", (*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 --------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - command_entry command_entries[] = { - {"-convert", &command_convert}, - {"-view", &command_view}, - {"-viewlist", &command_viewlist}, - {"-listcompatible", &command_listcompatible}}; - int index; - - if (argc < 2) - { - return print_usage(); - } - - 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]); - } - - return print_usage(); -} diff --git a/src/tools/ldresample.cpp b/src/tools/ldresample.cpp deleted file mode 100644 index f7c5fc8..0000000 --- a/src/tools/ldresample.cpp +++ /dev/null @@ -1,575 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Aaron Giles -/*************************************************************************** - - ldresample.c - - Laserdisc audio synchronizer and resampler. - -****************************************************************************/ - -#include "avhuff.h" -#include "bitmap.h" -#include "chd.h" -#include "vbiparse.h" - -#include -#include -#include -#include -#include -#include - - - -//************************************************************************** -// CONSTANTS -//************************************************************************** - -// size of window where we scan ahead to find maximum; this should be large enough to -// catch peaks of even slow waves -const uint32_t MAXIMUM_WINDOW_SIZE = 40; - -// number of standard deviations away from silence that we consider a real signal -const uint32_t SIGNAL_DEVIATIONS = 100; - -// number of standard deviations away from silence that we consider the start of a signal -const uint32_t SIGNAL_START_DEVIATIONS = 5; - -// number of consecutive entries of signal before we consider that we found it -const uint32_t MINIMUM_SIGNAL_COUNT = 20; - - - -//************************************************************************** -// TYPE DEFINITIONS -//************************************************************************** - -struct movie_info -{ - double framerate; - int iframerate; - int numfields; - int width; - int height; - int samplerate; - int channels; - int interlaced; - bitmap_yuy16 bitmap; - std::vector lsound; - std::vector rsound; - uint32_t samples; -}; - - -// ======================> chd_resample_compressor - -class chd_resample_compressor : public chd_file_compressor -{ -public: - // construction/destruction - chd_resample_compressor(chd_file &source, movie_info &info, int64_t ioffset, int64_t islope) - : m_source(source), - m_info(info), - m_ioffset(ioffset), - m_islope(islope) { } - - // read interface - virtual uint32_t read_data(void *_dest, uint64_t offset, uint32_t length) - { - assert(offset % m_source.hunk_bytes() == 0); - assert(length % m_source.hunk_bytes() == 0); - - uint32_t startfield = offset / m_source.hunk_bytes(); - uint32_t endfield = startfield + length / m_source.hunk_bytes(); - uint8_t *dest = reinterpret_cast(_dest); - - for (uint32_t fieldnum = startfield; fieldnum < endfield; fieldnum++) - { - generate_one_frame(dest, m_source.hunk_bytes(), fieldnum); - dest += m_source.hunk_bytes(); - } - return length; - } - -private: - // internal helpers - void generate_one_frame(uint8_t *dest, uint32_t datasize, uint32_t fieldnum); - - // internal state - chd_file & m_source; - movie_info & m_info; - int64_t m_ioffset; - int64_t m_islope; -}; - - - -//************************************************************************** -// INLINE FUNCTIONS -//************************************************************************** - -//------------------------------------------------- -// field_to_sample_number - given a field number -// compute the absolute sample number for the -// first sample of that field -//------------------------------------------------- - -inline uint32_t field_to_sample_number(const movie_info &info, uint32_t field) -{ - return (uint64_t(info.samplerate) * uint64_t(field) * uint64_t(1000000) + info.iframerate - 1) / uint64_t(info.iframerate); -} - - -//------------------------------------------------- -// sample_number_to_field - given a sample number -// compute the field where it is located and -// the offset within the field -//------------------------------------------------- - -inline uint32_t sample_number_to_field(const movie_info &info, uint32_t samplenum, uint32_t &offset) -{ - uint32_t guess = (uint64_t(samplenum) * uint64_t(info.iframerate) + (uint64_t(info.samplerate) * uint64_t(1000000) - 1)) / (uint64_t(info.samplerate) * uint64_t(1000000)); - while (1) - { - uint32_t fieldstart = field_to_sample_number(info, guess); - uint32_t fieldend = field_to_sample_number(info, guess + 1); - if (samplenum >= fieldstart && samplenum < fieldend) - { - offset = samplenum - fieldstart; - return guess; - } - else if (samplenum < fieldstart) - guess--; - else - guess++; - } -} - - - -//************************************************************************** -// CHD HANDLING -//************************************************************************** - -//------------------------------------------------- -// open_chd - open a CHD file and return -// information about it -//------------------------------------------------- - -static std::error_condition open_chd(chd_file &file, const char *filename, movie_info &info) -{ - // open the file - std::error_condition chderr = file.open(filename); - if (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) - { - fprintf(stderr, "Error getting A/V metadata: %s\n", chderr.message().c_str()); - return chderr; - } - - // extract the info - int fps, fpsfrac, width, height, interlaced, channels, rate; - if (sscanf(metadata.c_str(), AV_METADATA_FORMAT, &fps, &fpsfrac, &width, &height, &interlaced, &channels, &rate) != 7) - { - fprintf(stderr, "Improperly formatted metadata\n"); - return chd_file::error::INVALID_METADATA; - } - - // extract movie info - info.iframerate = fps * 1000000 + fpsfrac; - info.framerate = info.iframerate / 1000000.0; - info.numfields = file.hunk_count(); - info.width = width; - info.height = height; - info.interlaced = interlaced; - info.samplerate = rate; - info.channels = channels; - - // allocate buffers - info.bitmap.resize(info.width, info.height); - info.lsound.resize(info.samplerate); - info.rsound.resize(info.samplerate); - return std::error_condition(); -} - - -//------------------------------------------------- -// create_chd - create a new CHD file -//------------------------------------------------- - -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 }; - 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", chderr.message().c_str()); - return chderr; - } - - // clone the metadata - chderr = file.clone_all_metadata(source); - if (chderr) - { - fprintf(stderr, "Error cloning metadata: %s\n", chderr.message().c_str()); - return chderr; - } - - // begin compressing - file.compress_begin(); - return std::error_condition(); -} - - -//------------------------------------------------- -// read_chd - read a field from a CHD file -//------------------------------------------------- - -static bool read_chd(chd_file &file, uint32_t field, movie_info &info, uint32_t soundoffs) -{ - // configure the codec - avhuff_decoder::config avconfig; - avconfig.video = &info.bitmap; - avconfig.maxsamples = info.lsound.size(); - avconfig.actsamples = &info.samples; - avconfig.audio[0] = &info.lsound[soundoffs]; - avconfig.audio[1] = &info.rsound[soundoffs]; - - // configure the decompressor for this field - file.codec_configure(CHD_CODEC_AVHUFF, AVHUFF_CODEC_DECOMPRESS_CONFIG, &avconfig); - - // read the field - std::error_condition chderr = file.read_hunk(field, nullptr); - return !chderr; -} - - - -//************************************************************************** -// CORE IMPLEMENTATION -//************************************************************************** - -//------------------------------------------------- -// find_edge_near_field - given a field number, -// load +/- 1/2 second on either side and find -// an audio edge -//------------------------------------------------- - -static bool find_edge_near_field(chd_file &srcfile, uint32_t fieldnum, movie_info &info, bool report_best_field, int32_t &delta) -{ - // clear the sound buffers - memset(&info.lsound[0], 0, info.lsound.size() * 2); - memset(&info.rsound[0], 0, info.rsound.size() * 2); - - // read 1 second around the target area - int fields_to_read = info.iframerate / 1000000; - int32_t firstfield = fieldnum - (fields_to_read / 2); - uint32_t targetsoundstart = 0; - uint32_t firstfieldend = 0; - uint32_t fieldstart[100]; - uint32_t soundend = 0; - for (int32_t curfield = 0; curfield < fields_to_read; curfield++) - { - // remember the start of each field - fieldstart[curfield] = soundend; - - // remember the sound offset where the initial fieldnum is - if (firstfield + curfield == fieldnum) - targetsoundstart = soundend; - - // read the frame and samples - if (firstfield + curfield >= 0) - { - read_chd(srcfile, firstfield + curfield, info, soundend); - soundend += info.samples; - - // also remember the offset at the end of the first field - if (firstfieldend == 0) - firstfieldend = soundend; - } - } - - // compute absolute deltas across the samples - for (uint32_t sampnum = 0; sampnum < soundend; sampnum++) - { - info.lsound[sampnum] = labs(info.lsound[sampnum + 1] - info.lsound[sampnum]); - info.rsound[sampnum] = labs(info.rsound[sampnum + 1] - info.rsound[sampnum]); - } - - // for each sample in the collection, find the highest deltas over the - // next few samples, and take the nth highest value (to remove outliers) - for (uint32_t sampnum = 0; sampnum < soundend - MAXIMUM_WINDOW_SIZE; sampnum++) - { - // scan forward over the maximum window - uint32_t lmax = 0, rmax = 0; - for (uint32_t scannum = 0; scannum < MAXIMUM_WINDOW_SIZE; scannum++) - { - if (info.lsound[sampnum + scannum] > lmax) - lmax = info.lsound[sampnum + scannum]; - if (info.rsound[sampnum + scannum] > rmax) - rmax = info.rsound[sampnum + scannum]; - } - - // replace this sample with the maximum value found - info.lsound[sampnum] = lmax; - info.rsound[sampnum] = rmax; - } - - // now compute the average over the first field, which is assumed to be silence - uint32_t firstlavg = 0; - uint32_t firstravg = 0; - for (uint32_t sampnum = 0; sampnum < firstfieldend; sampnum++) - { - firstlavg += info.lsound[sampnum]; - firstravg += info.rsound[sampnum]; - } - firstlavg /= firstfieldend; - firstravg /= firstfieldend; - - // then compute the standard deviation over the first field - uint32_t firstldev = 0; - uint32_t firstrdev = 0; - for (uint32_t sampnum = 0; sampnum < firstfieldend; sampnum++) - { - firstldev += (info.lsound[sampnum] - firstlavg) * (info.lsound[sampnum] - firstlavg); - firstrdev += (info.rsound[sampnum] - firstravg) * (info.rsound[sampnum] - firstravg); - } - firstldev = sqrt(double(firstldev) / firstfieldend); - firstrdev = sqrt(double(firstrdev) / firstfieldend); - - // scan forward through the samples, counting consecutive samples more than - // SIGNAL_DEVIATIONS standard deviations away from silence - uint32_t lcount = 0; - uint32_t rcount = 0; - uint32_t sampnum = 0; - for (sampnum = 0; sampnum < soundend; sampnum++) - { - // left speaker - if (info.lsound[sampnum] > firstlavg + SIGNAL_DEVIATIONS * firstldev) - lcount++; - else - lcount = 0; - - // right speaker - if (info.rsound[sampnum] > firstravg + SIGNAL_DEVIATIONS * firstrdev) - rcount++; - else - rcount = 0; - - // stop if we find enough - if (lcount > MINIMUM_SIGNAL_COUNT || rcount > MINIMUM_SIGNAL_COUNT) - break; - } - - // if we didn't find any, return failure - if (sampnum >= soundend) - { - if (!report_best_field) - printf("Field %5d: Unable to find edge\n", fieldnum); - return false; - } - - // scan backwards to find the start of the signal - for ( ; sampnum > 0; sampnum--) - if (info.lsound[sampnum - 1] < firstlavg + SIGNAL_START_DEVIATIONS * firstldev || - info.rsound[sampnum - 1] < firstravg + SIGNAL_START_DEVIATIONS * firstrdev) - break; - - // if we're to report the best field, figure out which field we are in - if (report_best_field) - { - int32_t curfield; - for (curfield = 0; curfield < fields_to_read - 1; curfield++) - if (sampnum < fieldstart[curfield + 1]) - break; - printf("Field %5d: Edge found at offset %d (frame %.1f)\n", firstfield + curfield, sampnum - fieldstart[curfield], (double)(firstfield + curfield) * 0.5); - } - - // otherwise, compute the delta from the provided field number - else - { - printf("Field %5d: Edge at offset %d from expected (found at %d, expected %d)\n", fieldnum, sampnum - targetsoundstart, sampnum, targetsoundstart); - delta = sampnum - targetsoundstart; - } - return true; -} - - -//------------------------------------------------- -// generate_one_frame - generate a single -// resampled frame -//------------------------------------------------- - -void chd_resample_compressor::generate_one_frame(uint8_t *dest, uint32_t datasize, uint32_t fieldnum) -{ - // determine the first field needed to cover this range of samples - uint32_t srcbegin = field_to_sample_number(m_info, fieldnum); - int64_t dstbegin = (int64_t(srcbegin) << 24) + m_ioffset + m_islope * fieldnum; - uint32_t dstbeginoffset; - int32_t dstbeginfield; - if (dstbegin >= 0) - dstbeginfield = sample_number_to_field(m_info, dstbegin >> 24, dstbeginoffset); - else - { - dstbeginfield = -1 - sample_number_to_field(m_info, -dstbegin >> 24, dstbeginoffset); - dstbeginoffset = (field_to_sample_number(m_info, -dstbeginfield) - field_to_sample_number(m_info, -dstbeginfield - 1)) - dstbeginoffset; - } - - // determine the last field needed to cover this range of samples - uint32_t srcend = field_to_sample_number(m_info, fieldnum + 1); - int64_t dstend = (int64_t(srcend) << 24) + m_ioffset + m_islope * (fieldnum + 1); - uint32_t dstendoffset; - int32_t dstendfield; - if (dstend >= 0) - dstendfield = sample_number_to_field(m_info, dstend >> 24, dstendoffset); - else - { - dstendfield = -1 - -sample_number_to_field(m_info, -dstend >> 24, dstendoffset); - dstendoffset = (field_to_sample_number(m_info, -dstendfield) - field_to_sample_number(m_info, -dstendfield - 1)) - dstendoffset; - } -/* -printf("%5d: start=%10d (%5d.%03d) end=%10d (%5d.%03d)\n", - fieldnum, - (int32_t)(dstbegin >> 24), dstbeginfield, dstbeginoffset, - (int32_t)(dstend >> 24), dstendfield, dstendoffset); -*/ - // read all samples required into the end of the sound buffers - uint32_t dstoffset = srcend - srcbegin; - for (int32_t dstfield = dstbeginfield; dstfield <= dstendfield; dstfield++) - { - if (dstfield >= 0) - read_chd(m_source, dstfield, m_info, dstoffset); - else - { - m_info.samples = field_to_sample_number(m_info, -dstfield) - field_to_sample_number(m_info, -dstfield - 1); - memset(&m_info.lsound[dstoffset], 0, m_info.samples * sizeof(m_info.lsound[0])); - memset(&m_info.rsound[dstoffset], 0, m_info.samples * sizeof(m_info.rsound[0])); - } - dstoffset += m_info.samples; - } - - // resample the destination samples to the source - dstoffset = srcend - srcbegin; - int64_t dstpos = dstbegin; - int64_t dststep = (dstend - dstbegin) / int64_t(srcend - srcbegin); - for (uint32_t srcoffset = 0; srcoffset < srcend - srcbegin; srcoffset++) - { - m_info.lsound[srcoffset] = m_info.lsound[(int)(dstoffset + dstbeginoffset + (dstpos >> 24) - (dstbegin >> 24))]; - m_info.rsound[srcoffset] = m_info.rsound[(int)(dstoffset + dstbeginoffset + (dstpos >> 24) - (dstbegin >> 24))]; - dstpos += dststep; - } - - // read the original frame, pointing the sound buffer past where we've calculated - read_chd(m_source, fieldnum, m_info, srcend - srcbegin); - - // assemble the final frame - std::vector buffer; - int16_t *sampledata[2] = { &m_info.lsound[0], &m_info.rsound[0] }; - avhuff_encoder::assemble_data(buffer, m_info.bitmap, m_info.channels, m_info.samples, sampledata); - memcpy(dest, &buffer[0], std::min(buffer.size(), size_t(datasize))); - if (buffer.size() < datasize) - memset(&dest[buffer.size()], 0, datasize - buffer.size()); -} - - -//------------------------------------------------- -// usage - display program usage -//------------------------------------------------- - -static int usage(void) -{ - fprintf(stderr, "Usage: \n"); - fprintf(stderr, " ldresample source.chd\n"); - fprintf(stderr, " ldresample source.chd output.chd offset [slope]\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "Where offset and slope make a linear equation f(x) which\n"); - fprintf(stderr, "describes the sample offset from the source as a function\n"); - fprintf(stderr, "of field number.\n"); - return 1; -} - - -//------------------------------------------------- -// main - main entry point -//------------------------------------------------- - -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]); - double slope = (argc < 5) ? 1.0 : atof(argv[4]); - - // print basic information - printf("Input file: %s\n", srcfilename); - if (dstfilename != nullptr) - { - printf("Output file: %s\n", dstfilename); - printf("Offset: %f\n", offset); - printf("Slope: %f\n", slope); - } - - // open the source file - chd_file srcfile; - movie_info info; - std::error_condition err = open_chd(srcfile, srcfilename, info); - if (err) - { - fprintf(stderr, "Unable to open file '%s'\n", srcfilename); - return 1; - } - - // output some basics - printf("Video dimensions: %dx%d\n", info.width, info.height); - printf("Video frame rate: %.2fHz\n", info.framerate); - 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) - { - for (uint32_t fieldnum = 60; fieldnum < info.numfields - 60; fieldnum += 30) - { - fprintf(stderr, "Field %5d\r", fieldnum); - int32_t delta; - find_edge_near_field(srcfile, fieldnum, info, true, delta); - } - } - - // otherwise, resample the source to the destination - else - { - // 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()) - { - fprintf(stderr, "Unable to create file '%s'\n", dstfilename); - return 1; - } - - // loop over all the fields in the source file - double progress, ratio; - osd_ticks_t last_update = 0; - while (dstfile.compress_continue(progress, ratio) == chd_file::error::COMPRESSING) - if (osd_ticks() - last_update > osd_ticks_per_second() / 4) - { - last_update = osd_ticks(); - printf("Processing, %.1f%% complete....\r", progress * 100.0); - } - } - return 0; -} diff --git a/src/tools/ldverify.cpp b/src/tools/ldverify.cpp deleted file mode 100644 index bb95c3f..0000000 --- a/src/tools/ldverify.cpp +++ /dev/null @@ -1,795 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Aaron Giles -/*************************************************************************** - - ldverify.c - - Laserdisc AVI/CHD verifier. - -****************************************************************************/ - -#include "avhuff.h" -#include "aviio.h" -#include "bitmap.h" -#include "chd.h" -#include "coretmpl.h" -#include "vbiparse.h" - -#include -#include -#include -#include -#include - - - -//************************************************************************** -// CONSTANTS -//************************************************************************** - -const int REPORT_BLANKS_THRESHOLD = 50; - - - -//************************************************************************** -// TYPE DEFINITIONS -//************************************************************************** - -struct movie_info -{ - double framerate; - int numframes; - int width; - int height; - int samplerate; - int channels; -}; - -struct video_info -{ - int first_whitefield; - bool saw_leadin; - bool saw_leadout; - int last_frame; - int last_chapter; - int cadence; - uint32_t cadence_history; - int prev_whitefield; - int min_overall; - int max_overall; - int first_blank_frame; - int first_blank_field; - int num_blank_fields; - int first_low_frame; - int first_low_field; - int num_low_fields; - int first_high_frame; - int first_high_field; - int num_high_fields; -}; - -struct audio_info -{ - int min_lsample; - int min_rsample; - int max_lsample; - int max_rsample; - int min_lsample_count; - int min_rsample_count; - int max_lsample_count; - int max_rsample_count; - int sample_count; -}; - - - -//************************************************************************** -// GLOBAL VARIABLES -//************************************************************************** - -static bool chdinterlaced; - - - -//************************************************************************** -// AVI HANDLING -//************************************************************************** - -//------------------------------------------------- -// open_avi - open an AVI file and return -// information about it -//------------------------------------------------- - -static void *open_avi(const char *filename, movie_info &info) -{ - // open the file - avi_file::ptr avi; - avi_file::error avierr = avi_file::open(filename, avi); - if (avierr != avi_file::error::NONE) - { - fprintf(stderr, "Error opening AVI file: %s\n", avi_file::error_string(avierr)); - return nullptr; - } - - // extract movie info - const avi_file::movie_info &aviinfo = avi->get_movie_info(); - info.framerate = (double)aviinfo.video_timescale / (double)aviinfo.video_sampletime; - info.numframes = aviinfo.video_numsamples; - info.width = aviinfo.video_width; - info.height = aviinfo.video_height; - info.samplerate = aviinfo.audio_samplerate; - info.channels = aviinfo.audio_channels; - return avi.release(); -} - - -//------------------------------------------------- -// read_avi - read a frame from an AVI file -//------------------------------------------------- - -static bool read_avi(void *file, int frame, bitmap_yuy16 &bitmap, int16_t *lsound, int16_t *rsound, int &samples) -{ - avi_file *avifile = reinterpret_cast(file); - - // read the frame - avi_file::error avierr = avifile->read_video_frame(frame, bitmap); - if (avierr != avi_file::error::NONE) - return false; - - // read the samples - const avi_file::movie_info &aviinfo = avifile->get_movie_info(); - uint32_t firstsample = (uint64_t(aviinfo.audio_samplerate) * uint64_t(frame) * uint64_t(aviinfo.video_sampletime) + aviinfo.video_timescale - 1) / uint64_t(aviinfo.video_timescale); - uint32_t lastsample = (uint64_t(aviinfo.audio_samplerate) * uint64_t(frame + 1) * uint64_t(aviinfo.video_sampletime) + aviinfo.video_timescale - 1) / uint64_t(aviinfo.video_timescale); - avierr = avifile->read_sound_samples(0, firstsample, lastsample - firstsample, lsound); - avierr = avifile->read_sound_samples(1, firstsample, lastsample - firstsample, rsound); - if (avierr != avi_file::error::NONE) - return false; - samples = lastsample - firstsample; - return true; -} - - -//------------------------------------------------- -// close_avi - close an AVI file -//------------------------------------------------- - -static void close_avi(void *file) -{ - avi_file *avifile = reinterpret_cast(file); - delete avifile; -} - - - -//************************************************************************** -// CHD HANDLING -//************************************************************************** - -//------------------------------------------------- -// open_chd - open a CHD file and return -// information about it -//------------------------------------------------- - -static void *open_chd(const char *filename, movie_info &info) -{ - auto chd = new chd_file; - - // open the file - std::error_condition chderr = chd->open(filename); - if (chderr) - { - fprintf(stderr, "Error opening CHD file: %s\n", chderr.message().c_str()); - delete chd; - return nullptr; - } - - // get the metadata - std::string metadata; - chderr = chd->read_metadata(AV_METADATA_TAG, 0, metadata); - if (chderr) - { - fprintf(stderr, "Error getting A/V metadata: %s\n", chderr.message().c_str()); - delete chd; - return nullptr; - } - - // extract the info - int fps, fpsfrac, width, height, interlaced, channels, rate; - if (sscanf(metadata.c_str(), AV_METADATA_FORMAT, &fps, &fpsfrac, &width, &height, &interlaced, &channels, &rate) != 7) - { - fprintf(stderr, "Improperly formatted metadata\n"); - delete chd; - return nullptr; - } - - // extract movie info - info.framerate = (fps * 1000000 + fpsfrac) / 1000000.0; - info.numframes = chd->hunk_count(); - info.width = width; - info.height = height; - info.samplerate = rate; - info.channels = channels; - - // convert to an interlaced frame - chdinterlaced = interlaced; - if (interlaced) - { - info.framerate /= 2; - info.numframes = (info.numframes + 1) / 2; - info.height *= 2; - } - return chd; -} - - -//------------------------------------------------- -// read_chd - read a frame from a CHD file -//------------------------------------------------- - -static int read_chd(void *file, int frame, bitmap_yuy16 &bitmap, int16_t *lsound, int16_t *rsound, int &samples) -{ - chd_file *chdfile = reinterpret_cast(file); - - // loop over fields - int interlace_factor = chdinterlaced ? 2 : 1; - samples = 0; - for (int fieldnum = 0; fieldnum < interlace_factor; fieldnum++) - { - // make a fake bitmap for this field - 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; - avconfig.maxsamples = 48000; - avconfig.actsamples = &numsamples; - avconfig.audio[0] = &lsound[samples]; - avconfig.audio[1] = &rsound[samples]; - - // configure the decompressor for this frame - chdfile->codec_configure(CHD_CODEC_AVHUFF, AVHUFF_CODEC_DECOMPRESS_CONFIG, &avconfig); - - // read the frame - std::error_condition chderr = chdfile->read_hunk(frame * interlace_factor + fieldnum, nullptr); - if (chderr) - return false; - - // account for samples read - samples += numsamples; - } - return true; -} - - -//------------------------------------------------- -// close_chd - close a CHD file -//------------------------------------------------- - -static void close_chd(void *file) -{ - chd_file *chdfile = reinterpret_cast(file); - delete chdfile; -} - - - -//************************************************************************** -// CORE IMPLEMENTATION -//************************************************************************** - -//------------------------------------------------- -// init_video - init video info structure -//------------------------------------------------- - -static void init_video(video_info &video) -{ - video.first_whitefield = -1; - video.saw_leadin = false; - video.saw_leadout = false; - video.last_frame = -1; - video.last_chapter = -1; - video.cadence = -1; - video.cadence_history = 0; - video.prev_whitefield = -1; - video.min_overall = 255; - video.max_overall = 0; - video.first_blank_frame = -1; - video.first_blank_field = -1; - video.num_blank_fields = -1; - video.first_low_frame = -1; - video.first_low_field = -1; - video.num_low_fields = -1; - video.first_high_frame = -1; - video.first_high_field = -1; - video.num_high_fields = -1; -} - - -//------------------------------------------------- -// verify_video - verify video frame -//------------------------------------------------- - -static void verify_video(video_info &video, int frame, bitmap_yuy16 &bitmap) -{ - // loop over fields - const int fields_per_frame = 2; - for (int fieldnum = 0; fieldnum < fields_per_frame; fieldnum++) - { - // output status - if (frame % 10 == 0 && fieldnum == 0) - fprintf(stderr, "%6d.%d...\r", frame, fieldnum); - - // parse the VBI data - vbi_metadata 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) - { - printf("%6d.%d: line 17 and 18 data does not match (17=%06X 18=%06X) (WARNING)\n", frame, fieldnum, metadata.line17, metadata.line18); - printf("%6d.%d: selected %06X based on bit confidence\n", frame, fieldnum, metadata.line1718); - } - - // is this a lead-in code? - if (metadata.line1718 == VBI_CODE_LEADIN) - { - // if we haven't seen lead-in yet, detect it - if (!video.saw_leadin) - { - video.saw_leadin = true; - printf("%6d.%d: lead-in code detected\n", frame, fieldnum); - } - - // if we've previously seen chapters/frames, that's weird - if (video.last_frame != -1 || video.last_chapter != -1) - printf("%6d.%d: lead-in code detected after frame/chapter data (WARNING)\n", frame, fieldnum); - } - - // is this a lead-out code? - if (metadata.line1718 == VBI_CODE_LEADOUT) - { - // if we haven't seen lead-in yet, detect it - if (!video.saw_leadout) - { - video.saw_leadout = true; - printf("%6d.%d: lead-out code detected\n", frame, fieldnum); - if (video.last_frame != -1) - printf("%6d.%d: final frame number was %d\n", frame, fieldnum, video.last_frame); - else - printf("%6d.%d: never detected any frame numbers (ERROR)\n", frame, fieldnum); - } - - // if we've previously seen chapters/frames, that's weird - if (video.last_frame == -1) - printf("%6d.%d: lead-out code detected with no frames detected beforehand (WARNING)\n", frame, fieldnum); - } - - // is this a frame code? - if ((metadata.line1718 & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE) - { - int framenum = VBI_CAV_PICTURE(metadata.line1718); - - // did we see any leadin? - if (!video.saw_leadin) - { - printf("%6d.%d: detected frame number but never saw any lead-in (WARNING)\n", frame, fieldnum); - video.saw_leadin = true; - } - - // if this is the first frame, make sure it's 1 - if (video.last_frame == -1) - { - if (framenum == 0) - printf("%6d.%d: detected frame 0\n", frame, fieldnum); - else if (framenum == 1) - printf("%6d.%d: detected frame 1\n", frame, fieldnum); - else - printf("%6d.%d: first frame number is not 0 or 1 (%d) (ERROR)\n", frame, fieldnum, framenum); - } - - // print an update every 10000 frames - if (framenum != 0 && framenum % 10000 == 0) - printf("%6d.%d: detected frame %d\n", frame, fieldnum, framenum); - - // if this frame is not consecutive, it's an error - if (video.last_frame != -1 && framenum != video.last_frame + 1) - printf("%6d.%d: gap in frame number sequence (%d->%d) (ERROR)\n", frame, fieldnum, video.last_frame, framenum); - - // remember the frame number - video.last_frame = framenum; - - // if we've seen a white flag before, but it's not here, warn - if (video.first_whitefield != -1 && !metadata.white) - printf("%6d.%d: detected frame number but no white flag (WARNING)\n", frame, fieldnum); - } - - // is the whiteflag set? - int field = frame * fields_per_frame + fieldnum; - if (metadata.white) - { - // if this is the first white flag we see, count it - if (video.first_whitefield == -1) - { - video.first_whitefield = field; - printf("%6d.%d: first white flag seen\n", frame, fieldnum); - } - - // if we've seen frame numbers before, but not here, warn - if (video.last_frame != -1 && (metadata.line1718 & VBI_MASK_CAV_PICTURE) != VBI_CODE_CAV_PICTURE) - printf("%6d.%d: detected white flag but no frame number (WARNING)\n", frame, fieldnum); - } - - // if this is the start of a frame, handle cadence - if (metadata.white || (metadata.line1718 & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE) - { - // if we've seen frames, but we're not yet to the lead-out, check the cadence - if (video.last_frame != -1 && !video.saw_leadout) - { - // make sure we have a proper history - if (video.prev_whitefield != -1) - video.cadence_history = (video.cadence_history << 4) | ((field - video.prev_whitefield) & 0x0f); - video.prev_whitefield = field; - - // if we don't know our cadence yet, determine it - if (video.cadence == -1 && (video.cadence_history & 0xf00) != 0) - { - if ((video.cadence_history & 0xfff) == 0x222) - { - printf("%6d.%d: detected 2:2 cadence\n", frame, fieldnum); - video.cadence = 4; - } - else if ((video.cadence_history & 0xfff) == 0x323) - { - printf("%6d.%d: detected 3:2 cadence\n", frame, fieldnum); - video.cadence = 5; - } - else if ((video.cadence_history & 0xfff) == 0x232) - { - printf("%6d.%d: detected 2:3 cadence\n", frame, fieldnum); - video.cadence = 5; - } - else - { - printf("%6d.%d: unknown cadence (history %d:%d:%d) (WARNING)\n", frame, fieldnum, - (video.cadence_history >> 8) & 15, (video.cadence_history >> 4) & 15, video.cadence_history & 15); - } - } - - // if we know our cadence, make sure we stick to it - if (video.cadence != -1) - { - if (video.cadence == 4 && (video.cadence_history & 0xfff) != 0x222) - { - printf("%6d.%d: missed cadence (history %d:%d:%d) (WARNING)\n", frame, fieldnum, - (video.cadence_history >> 8) & 15, (video.cadence_history >> 4) & 15, video.cadence_history & 15); - video.cadence = -1; - video.cadence_history = 0; - } - else if (video.cadence == 5 && (video.cadence_history & 0xfff) != 0x323 && (video.cadence_history & 0xfff) != 0x232) - { - printf("%6d.%d: missed cadence (history %d:%d:%d) (WARNING)\n", frame, fieldnum, - (video.cadence_history >> 8) & 15, (video.cadence_history >> 4) & 15, video.cadence_history & 15); - video.cadence = -1; - video.cadence_history = 0; - } - } - } - } - - // now examine the active video signal - uint32_t yhisto[256] = { 0 }; - uint32_t crhisto[256] = { 0 }; - uint32_t cbhisto[256] = { 0 }; - int pixels = 0; - for (int y = 22*2 + fieldnum; y < bitmap.height(); y += 2) - { - for (int x = 16; x < 720 - 16; x++) - { - yhisto[bitmap.pix(y, x) >> 8]++; - if (x % 2 == 0) - cbhisto[bitmap.pix(y, x) & 0xff]++; - else - crhisto[bitmap.pix(y, x) & 0xff]++; - } - pixels += 720 - 16 - 16; - } - - // remove the top/bottom 0.1% of Y - int remaining = pixels / 1000; - int yminval; - for (yminval = 0; (remaining -= yhisto[yminval]) >= 0; yminval++) ; - remaining = pixels / 1000; - int ymaxval; - for (ymaxval = 255; (remaining -= yhisto[ymaxval]) >= 0; ymaxval--) ; - - // remove the top/bottom 0.1% of Cb - remaining = pixels / 500; - int cbminval; - for (cbminval = 0; (remaining -= cbhisto[cbminval]) >= 0; cbminval++) ; - remaining = pixels / 500; - int cbmaxval; - for (cbmaxval = 255; (remaining -= cbhisto[cbmaxval]) >= 0; cbmaxval--) ; - - // remove the top/bottom 0.1% of Cr - remaining = pixels / 500; - int crminval; - for (crminval = 0; (remaining -= crhisto[crminval]) >= 0; crminval++) ; - remaining = pixels / 500; - int crmaxval; - for (crmaxval = 255; (remaining -= crhisto[crmaxval]) >= 0; crmaxval--) ; - - // track blank frames - if (ymaxval - yminval < 10 && cbmaxval - cbminval < 10 && crmaxval - cbmaxval < 10) - { - if (video.first_blank_frame == -1) - { - video.first_blank_frame = frame; - video.first_blank_field = fieldnum; - video.num_blank_fields = 0; - } - video.num_blank_fields++; - } - else if (video.num_blank_fields > 0) - { - if (video.num_blank_fields >= REPORT_BLANKS_THRESHOLD) - printf("%6d.%d-%6d.%d: blank frames for %d fields (INFO)\n", video.first_blank_frame, video.first_blank_field, frame, fieldnum, video.num_blank_fields); - video.first_blank_frame = video.first_blank_field = video.num_blank_fields = -1; - } - - // update the overall min/max - video.min_overall = std::min(yminval, video.min_overall); - video.max_overall = std::max(ymaxval, video.max_overall); - - // track low fields - if (yminval <= 0) - { - if (video.first_low_frame == -1) - { - video.first_low_frame = frame; - video.first_low_field = fieldnum; - video.num_low_fields = 0; - } - video.num_low_fields++; - } - else if (video.num_low_fields > 0) - { - printf("%6d.%d-%6d.%d: active video signal level low for %d fields (WARNING)\n", video.first_low_frame, video.first_low_field, frame, fieldnum, video.num_low_fields); - video.first_low_frame = video.first_low_field = video.num_low_fields = -1; - } - - // track high fields - if (ymaxval >= 255) - { - if (video.first_high_frame == -1) - { - video.first_high_frame = frame; - video.first_high_field = fieldnum; - video.num_high_fields = 0; - } - video.num_high_fields++; - } - else if (video.num_high_fields > 0) - { - printf("%6d.%d-%6d.%d: active video signal level high for %d fields (WARNING)\n", video.first_high_frame, video.first_high_field, frame, fieldnum, video.num_high_fields); - video.first_high_frame = video.first_high_field = video.num_high_fields = -1; - } - } -} - - -//------------------------------------------------- -// verify_video_final - final verification -//------------------------------------------------- - -static void verify_video_final(video_info &video, int frame, bitmap_yuy16 &bitmap) -{ - int fields_per_frame = (bitmap.height() >= 288) ? 2 : 1; - int field = frame * fields_per_frame; - - // did we ever see any white flags? - if (video.first_whitefield == -1) - printf("Track %6d.%d: never saw any white flags (WARNING)\n", field / fields_per_frame, 0); - - // did we ever see any lead-out? - if (!video.saw_leadout) - printf("Track %6d.%d: never saw any lead-out (WARNING)\n", field / fields_per_frame, 0); - - // any remaining high/low reports? - if (video.num_blank_fields >= REPORT_BLANKS_THRESHOLD) - printf("%6d.%d-%6d.%d: blank frames for %d fields (INFO)\n", video.first_blank_frame, video.first_blank_field, frame, 0, video.num_blank_fields); - if (video.num_low_fields > 0) - printf("%6d.%d-%6d.%d: active video signal level low for %d fields (WARNING)\n", video.first_low_frame, video.first_low_field, frame, 0, video.num_low_fields); - if (video.num_high_fields > 0) - printf("%6d.%d-%6d.%d: active video signal level high for %d fields (WARNING)\n", video.first_high_frame, video.first_high_field, frame, 0, video.num_high_fields); - - // summary info - printf("\nVideo summary:\n"); - printf(" Overall video range: %d-%d (%02X-%02X)\n", video.min_overall, video.max_overall, video.min_overall, video.max_overall); -} - - -//------------------------------------------------- -// init_audio - init audio info structure -//------------------------------------------------- - -static void init_audio(audio_info &audio) -{ - audio.min_lsample = 32767; - audio.min_rsample = 32767; - audio.max_lsample = -32768; - audio.max_rsample = -32768; - audio.min_lsample_count = 0; - audio.min_rsample_count = 0; - audio.max_lsample_count = 0; - audio.max_rsample_count = 0; - audio.sample_count = 0; -} - - -//------------------------------------------------- -// verify_audio - verify audio data -//------------------------------------------------- - -static void verify_audio(audio_info &audio, const int16_t *lsound, const int16_t *rsound, int samples) -{ - // count the overall samples - audio.sample_count += samples; - - // iterate over samples, tracking min/max - for (int sampnum = 0; sampnum < samples; sampnum++) - { - // did we hit a minimum on the left? - if (lsound[sampnum] < audio.min_lsample) - { - audio.min_lsample = lsound[sampnum]; - audio.min_lsample_count = 1; - } - else if (lsound[sampnum] == audio.min_lsample) - audio.min_lsample_count++; - - // did we hit a maximum on the left? - if (lsound[sampnum] > audio.max_lsample) - { - audio.max_lsample = lsound[sampnum]; - audio.max_lsample_count = 1; - } - else if (lsound[sampnum] == audio.max_lsample) - audio.max_lsample_count++; - - // did we hit a minimum on the right? - if (rsound[sampnum] < audio.min_rsample) - { - audio.min_rsample = rsound[sampnum]; - audio.min_rsample_count = 1; - } - else if (rsound[sampnum] == audio.min_rsample) - audio.min_rsample_count++; - - // did we hit a maximum on the right? - if (rsound[sampnum] > audio.max_rsample) - { - audio.max_rsample = rsound[sampnum]; - audio.max_rsample_count = 1; - } - else if (rsound[sampnum] == audio.max_rsample) - audio.max_rsample_count++; - } -} - - -//------------------------------------------------- -// verify_audio_final - final verification -//------------------------------------------------- - -static void verify_audio_final(audio_info &audio) -{ - printf("\nAudio summary:\n"); - printf(" Overall channel 0 range: %d-%d (%04X-%04X)\n", audio.min_lsample, audio.max_lsample, uint16_t(audio.min_lsample), uint16_t(audio.max_lsample)); - printf(" Overall channel 1 range: %d-%d (%04X-%04X)\n", audio.min_rsample, audio.max_rsample, uint16_t(audio.min_rsample), uint16_t(audio.max_rsample)); -} - - -//------------------------------------------------- -// usage - display program usage -//------------------------------------------------- - -static int usage(void) -{ - fprintf(stderr, "Usage: \n"); - fprintf(stderr, " ldverify \n"); - return 1; -} - - -//------------------------------------------------- -// main - main entry point -//------------------------------------------------- - -int main(int argc, char *argv[]) -{ - try - { - // init globals - audio_info audio; - init_audio(audio); - video_info video; - init_video(video); - - // verify arguments - if (argc < 2) - return usage(); - const char *srcfile = argv[1]; - - // check extension of file - int srcfilelen = strlen(srcfile); - if (srcfilelen < 4) - return usage(); - bool isavi; - if (tolower((uint8_t)srcfile[srcfilelen-3]) == 'a' && tolower((uint8_t)srcfile[srcfilelen-2]) == 'v' && tolower((uint8_t)srcfile[srcfilelen-1]) == 'i') - isavi = true; - else if (tolower((uint8_t)srcfile[srcfilelen-3]) == 'c' && tolower((uint8_t)srcfile[srcfilelen-2]) == 'h' && tolower((uint8_t)srcfile[srcfilelen-1]) == 'd') - isavi = false; - else - return usage(); - - // open the file - printf("Processing file: %s\n", srcfile); - movie_info info = { 0 }; - void *file = isavi ? open_avi(srcfile, info) : open_chd(srcfile, info); - if (file == nullptr) - { - fprintf(stderr, "Unable to open file '%s'\n", srcfile); - return 1; - } - - // comment on the video dimensions - printf("Video dimensions: %dx%d\n", info.width, info.height); - if (info.width != 720) - printf("WARNING: Unexpected video width (should be 720)\n"); - if (info.height != 524) - printf("WARNING: Unexpected video height (should be 262 or 524)\n"); - - // comment on the video frame rate - printf("Video frame rate: %.2fHz\n", info.framerate); - if (int(info.framerate * 100.0 + 0.5) != 2997) - printf("WARNING: Unexpected frame rate (should be 29.97Hz)\n"); - - // comment on the sample rate - printf("Sample rate: %dHz\n", info.samplerate); - if (info.samplerate != 48000) - printf("WARNING: Unexpected sampele rate (should be 48000Hz)\n"); - - // allocate a bitmap - bitmap_yuy16 bitmap(info.width, info.height); - - // allocate sound buffers - std::vector lsound(info.samplerate); - std::vector rsound(info.samplerate); - - // loop over frames - int frame = 0; - int samples = 0; - while (isavi ? read_avi(file, frame, bitmap, &lsound[0], &rsound[0], samples) : read_chd(file, frame, bitmap, &lsound[0], &rsound[0], samples)) - { - verify_video(video, frame, bitmap); - verify_audio(audio, &lsound[0], &rsound[0], samples); - frame++; - } - - // close the files - isavi ? close_avi(file) : close_chd(file); - - // final output - verify_video_final(video, frame, bitmap); - verify_audio_final(audio); - } - catch (std::bad_alloc &) - { - fprintf(stderr, "Out of memory allocating memory\n"); - return 1; - } - - return 0; -} diff --git a/src/tools/pngcmp.cpp b/src/tools/pngcmp.cpp deleted file mode 100644 index 480f9fa..0000000 --- a/src/tools/pngcmp.cpp +++ /dev/null @@ -1,200 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Aaron Giles -/*************************************************************************** - - pngcmp.c - - PNG comparison (based on regrep.c) - -****************************************************************************/ - -#include "corefile.h" -#include "png.h" - -#include "osdfile.h" - -#include -#include -#include -#include -#include -#include - - -/*************************************************************************** - CONSTANTS & DEFINES -***************************************************************************/ - -#define BITMAP_SPACE 4 - -/*************************************************************************** - PROTOTYPES -***************************************************************************/ - -static int generate_png_diff(const std::string& imgfile1, const std::string& imgfile2, const std::string& outfilename); - -/*************************************************************************** - MAIN -***************************************************************************/ - -/*------------------------------------------------- - main - main entry point --------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - /* first argument is the directory */ - if (argc < 4) - { - fprintf(stderr, "Usage:\npngcmp \n"); - return 10; - } - std::string imgfilename1(argv[1]); - std::string imgfilename2(argv[2]); - std::string outfilename(argv[3]); - - try { - return generate_png_diff(imgfilename1, imgfilename2, outfilename); - } - catch(...) - { - printf("Exception occurred"); - return 1000; - } -} - -/*------------------------------------------------- - generate_png_diff - create a new PNG file - that shows multiple differing PNGs side by - side with a third set of differences --------------------------------------------------*/ - -static int generate_png_diff(const std::string& imgfile1, const std::string& imgfile2, const std::string& outfilename) -{ - bitmap_argb32 bitmap1; - bitmap_argb32 bitmap2; - bitmap_argb32 finalbitmap; - int width, height, maxwidth; - util::core_file::ptr file; - std::error_condition filerr; - int error = 100; - - /* open the source image */ - filerr = util::core_file::open(imgfile1, OPEN_FLAG_READ, file); - if (filerr) - { - printf("Could not open %s (%s)\n", imgfile1.c_str(), filerr.message().c_str()); - goto error; - } - - /* load the source image */ - filerr = util::png_read_bitmap(*file, bitmap1); - file.reset(); - if (filerr) - { - 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) - { - printf("Could not open %s (%s)\n", imgfile2.c_str(), filerr.message().c_str()); - goto error; - } - - /* load the source image */ - filerr = util::png_read_bitmap(*file, bitmap2); - file.reset(); - if (filerr) - { - 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 (int y = 0; y < bitmap2.height() && !bitmaps_differ; 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; - bitmaps_differ = (x != bitmap2.width()); - } - - if (bitmaps_differ) - { - /* determine the size of the final bitmap */ - height = width = 0; - { - /* determine the maximal width */ - maxwidth = std::max(bitmap1.width(), bitmap2.width()); - width = bitmap1.width() + BITMAP_SPACE + maxwidth + BITMAP_SPACE + maxwidth; - - /* add to the height */ - height += std::max(bitmap1.height(), bitmap2.height()); - } - - /* allocate the final bitmap */ - finalbitmap.allocate(width, height); - - /* now copy and compare each set of bitmaps */ - int curheight = std::max(bitmap1.height(), bitmap2.height()); - /* iterate over rows in these bitmaps */ - for (int y = 0; y < curheight; y++) - { - 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 (int x = 0; x < maxwidth; x++) - { - int pix1 = -1, pix2 = -2; - - if (src1 != nullptr && x < bitmap1.width()) - pix1 = dst1[x] = src1[x]; - if (src2 != nullptr && x < bitmap2.width()) - pix2 = dst2[x] = src2[x]; - dstdiff[x] = (pix1 != pix2) ? 0xffffffff : 0xff000000; - } - } - - /* write the final PNG */ - filerr = util::core_file::open(outfilename, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, file); - if (filerr) - { - printf("Could not open %s (%s)\n", outfilename.c_str(), filerr.message().c_str()); - goto error; - } - filerr = util::png_write_bitmap(*file, nullptr, finalbitmap, 0, nullptr); - file.reset(); - if (filerr) - { - printf("Could not write %s (%s)\n", outfilename.c_str(), filerr.message().c_str()); - goto error; - } - } - - /* if we get here, we are error free */ - if (bitmaps_differ) - error = 1; - else - error = 0; - -error: - if (error == -1) - osd_file::remove(outfilename); - return error; -} diff --git a/src/tools/regrep.cpp b/src/tools/regrep.cpp deleted file mode 100644 index b18b6b1..0000000 --- a/src/tools/regrep.cpp +++ /dev/null @@ -1,1113 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Aaron Giles -/*************************************************************************** - - Regression test report generator - -****************************************************************************/ - -#include "corefile.h" -#include "corestr.h" -#include "png.h" - -#include "osdcomm.h" - -#include -#include -#include -#include -#include -#include - - -using util::string_format; - - -/*************************************************************************** - CONSTANTS & DEFINES -***************************************************************************/ - -#define MAX_COMPARES 16 -#define BITMAP_SPACE 4 - -enum -{ - STATUS_NOT_PRESENT = 0, - STATUS_SUCCESS, - STATUS_SUCCESS_DIFFERENT, - STATUS_MISSING_FILES, - STATUS_EXCEPTION, - STATUS_FATAL_ERROR, - STATUS_FAILED_VALIDITY, - STATUS_OTHER, - STATUS_COUNT -}; - -enum -{ - BUCKET_UNKNOWN = 0, - BUCKET_IMPROVED, - BUCKET_REGRESSED, - BUCKET_CHANGED, - BUCKET_MULTI_ERROR, - BUCKET_CONSISTENT_ERROR, - BUCKET_GOOD, - BUCKET_GOOD_BUT_CHANGED, - BUCKET_GOOD_BUT_CHANGED_SCREENSHOTS, - BUCKET_COUNT -}; - - - -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ - -struct summary_file -{ - summary_file * next; - char name[20]; - char source[100]; - uint8_t status[MAX_COMPARES]; - uint8_t matchbitmap[MAX_COMPARES]; - std::string text[MAX_COMPARES]; -}; - - -struct summary_list -{ - summary_list * next; - summary_file * files; - char * dir; - char version[40]; -}; - - - -/*************************************************************************** - GLOBAL VARIABLES -***************************************************************************/ - -static summary_file *filehash[128][128]; -static summary_list lists[MAX_COMPARES]; -static int list_count; - -static const char *const bucket_name[] = -{ - "Unknown", - "Games That Have Improved", - "Games That Have Regressed", - "Games With Changed Screenshots", - "Games With Multiple Errors", - "Games With Consistent Errors", - "Games That Are Consistently Good", - "Games That Regressed But Improved", - "Games With Changed Screenshots", -}; - -static const int bucket_output_order[] = -{ - BUCKET_REGRESSED, - BUCKET_IMPROVED, - BUCKET_CHANGED, - BUCKET_GOOD_BUT_CHANGED_SCREENSHOTS, - BUCKET_GOOD_BUT_CHANGED, - BUCKET_MULTI_ERROR, - BUCKET_CONSISTENT_ERROR -}; - -static const char *const status_text[] = -{ - "", - "Success", - "Changed", - "Missing Files", - "Exception", - "Fatal Error", - "Failed Validity Check", - "Other Unknown Error" -}; - -static const char *const status_color[] = -{ - "", - "background:#00A000", - "background:#E0E000", - "background:#8000C0", - "background:#C00000", - "background:#C00000", - "background:#C06000", - "background:#C00000", - "background:#C00000", -}; - - - -/*************************************************************************** - PROTOTYPES -***************************************************************************/ - -/* summary parsing */ -static int read_summary_log(const char *filename, int index); -static summary_file *parse_driver_tag(char *linestart, int index); -static summary_file *get_file(const char *filename); -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::write_stream::ptr &&file, std::string &templatefile, std::string &title); - -/* report generators */ -static void output_report(std::string &dirname, std::string &tempheader, std::string &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); - - - -/*************************************************************************** - INLINE FUNCTIONS -***************************************************************************/ - -/*------------------------------------------------- - trim_string - trim leading/trailing spaces - from a string --------------------------------------------------*/ - -static inline char *trim_string(char *string) -{ - int length; - - /* trim leading spaces */ - while (*string != 0 && isspace((uint8_t)*string)) - string++; - - /* trim trailing spaces */ - length = strlen(string); - while (length > 0 && isspace((uint8_t)string[length - 1])) - string[--length] = 0; - - return string; -} - - -/*------------------------------------------------- - get_unique_index - get the unique bitmap - index for a given entry --------------------------------------------------*/ - -static inline int get_unique_index(const summary_file *curfile, int index) -{ - int listnum, curindex = 0; - - /* if we're invalid, just return that */ - if (curfile->matchbitmap[index] == 0xff) - return -1; - - /* count unique elements up to us */ - for (listnum = 0; listnum < curfile->matchbitmap[index]; listnum++) - if (curfile->matchbitmap[listnum] == listnum) - curindex++; - return curindex; -} - - - -/*************************************************************************** - MAIN -***************************************************************************/ - -/*------------------------------------------------- - main - main entry point --------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - uint32_t bufsize; - void *buffer; - int listnum; - int result; - - /* first argument is the directory */ - if (argc < 4) - { - fprintf(stderr, "Usage:\nregrep