Check "notification" against being nil, which is how we call it when we need to explicitly update the enabled state of the "create" button.
*/
@@ -32,8 +32,8 @@
/*!
@method showCreateResourceSheet:
@abstract Shows the sheet allowing the user to define the properties of a new resource.
-@updated 2003-08-01 UK: Made it "fake" a popup selection so type field and popup match.
-@updated 2003-08-01 UK: Made it suggest an unused resource ID.
+@change 2003-08-01 UK: Made it "fake" a popup selection so type field and popup match.
+@change 2003-08-01 UK: Made it suggest an unused resource ID.
*/
- (void)showCreateResourceSheet:(ResourceDocument *)sheetDoc
@@ -77,7 +77,7 @@
/*!
@method typePopupSelection:
@abstract Updates the edit text field when the type pop-up selection is changed.
-@updated 2003-08-01 UK: Commented, made it update state of "create" button.
+@change 2003-08-01 UK: Commented, made it update state of "create" button.
*/
- (IBAction)typePopupSelection:(id)sender
diff --git a/Cocoa/Classes/InfoWindowController.m b/Cocoa/Classes/InfoWindowController.m
index f1374ff..a8ca81f 100644
--- a/Cocoa/Classes/InfoWindowController.m
+++ b/Cocoa/Classes/InfoWindowController.m
@@ -36,9 +36,9 @@
/*!
@method updateInfoWindow
-@updated 2003-11-06 NGS: Fixed creator/type handling.
-@updated 2003-10-26 NGS: Now asks app delegate for icon instead of NSWorkspace.
-@updated 2003-10-26 NGS: Improved document name & icon display.
+@change 2003-11-06 NS: Fixed creator/type handling.
+@change 2003-10-26 NS: Now asks app delegate for icon instead of NSWorkspace.
+@change 2003-10-26 NS: Improved document name & icon display.
*/
- (void)updateInfoWindow
diff --git a/Cocoa/Classes/OutlineViewDelegate.m b/Cocoa/Classes/OutlineViewDelegate.m
index efae584..a1df4ac 100644
--- a/Cocoa/Classes/OutlineViewDelegate.m
+++ b/Cocoa/Classes/OutlineViewDelegate.m
@@ -56,7 +56,7 @@
/*!
@function compareResourcesAscending
-@updated 2003-10-25 NGS: now uses KVC methods to obtain the strings to compare
+@change 2003-10-25 NGS: now uses KVC methods to obtain the strings to compare
*/
int compareResourcesAscending(Resource *r1, Resource *r2, void *context)
@@ -71,7 +71,7 @@ int compareResourcesAscending(Resource *r1, Resource *r2, void *context)
/*!
@function compareResourcesDescending
-@updated 2003-10-25 NGS: now uses KVC methods to obtain the strings to compare
+@change 2003-10-25 NGS: now uses KVC methods to obtain the strings to compare
*/
int compareResourcesDescending(Resource *r1, Resource *r2, void *context)
@@ -93,9 +93,9 @@ int compareResourcesDescending(Resource *r1, Resource *r2, void *context)
/*!
@method outlineView:willDisplayCell:forTableColumn:item:
-@updated 2003-10-25 NGS: Moved functionality of NameFormatter into this method, removed NameFormatter class.
-@updated 2003-10-24 NGS: Swapped row colours so first row is white (as per 10.3), conditionalised drawing line background colours to system versions < 10.3, since in 10.3 it is handled by the nib file.
-@updated 2003-10-24 NGS: Added iconForResourceType method to app delegate instead of interrogating the cache here.
+@change 2003-10-25 NGS: Moved functionality of NameFormatter into this method, removed NameFormatter class.
+@change 2003-10-24 NGS: Swapped row colours so first row is white (as per 10.3), conditionalised drawing line background colours to system versions < 10.3, since in 10.3 it is handled by the nib file.
+@change 2003-10-24 NGS: Added iconForResourceType method to app delegate instead of interrogating the cache here.
@pending remove setting of the cell formatter when that capability is in interface builder
*/
diff --git a/Cocoa/Classes/RKEditorRegistry.m b/Cocoa/Classes/RKEditorRegistry.m
index 52e2e75..cc2e0e3 100644
--- a/Cocoa/Classes/RKEditorRegistry.m
+++ b/Cocoa/Classes/RKEditorRegistry.m
@@ -44,7 +44,7 @@
@method +defaultRegistry
@author Uli Kusterer
@created 2003-07-31
-@updated 2003-10-28 NGS: Changed method name from +mainRegistry (so it more closly matchs +defaultCenter) and moved global var inside method, making it a static.
+@change 2003-10-28 NS: Changed method name from +mainRegistry (so it more closly matchs +defaultCenter) and moved global var inside method, making it a static.
@description Returns the default plugin registry of this application, instantiating it first if there is none yet. As soon as this is instantiated, the plugins are loaded.
*/
+ (RKEditorRegistry *)defaultRegistry
@@ -74,7 +74,7 @@
@abstract (Re)loads our list of plugins. You can use this as an action for a menu item, if you want.
@author Uli Kusterer
@created 2003-07-31
-@updated 2003-10-28 NGS: Updated to look for more sophisticated RKSupportedTypes key in addition to (the now deprecated) RKEditedTypes.
+@change 2003-10-28 NGS: Updated to look for more sophisticated RKSupportedTypes key in addition to (the now deprecated) RKEditedTypes.
@pending Use NSSearchPathForDirectoriesInDomains() or equivalent to get folder paths instead of hard coding them.
@pending Currently, Cocoa classes can't be unloaded, which means we're
not leaking the NSBundles we load here. However, if this one
@@ -149,8 +149,8 @@
{
// get values for type entry
NSString *name = [typeEntry objectForKey:@"RKTypeName"];
- NSString *role = [typeEntry objectForKey:@"RKTypeRole"];
- BOOL isDefault = [(NSString *)[typeEntry objectForKey:@"IsResKnifeDefaultForType"] boolValue];
+// NSString *role = [typeEntry objectForKey:@"RKTypeRole"];
+// BOOL isDefault = [(NSString *)[typeEntry objectForKey:@"IsResKnifeDefaultForType"] boolValue];
// register them
[typeRegistry setObject:pluginClass forKey:name]; // bug: very primative, doesn't use extra data
diff --git a/Cocoa/Classes/RKSupportResourceRegistry.mm b/Cocoa/Classes/RKSupportResourceRegistry.mm
new file mode 100644
index 0000000..855493d
--- /dev/null
+++ b/Cocoa/Classes/RKSupportResourceRegistry.mm
@@ -0,0 +1,25 @@
+#import "RKSupportResourceRegistry.h"
+
+@implementation RKSupportResourceRegistry
+
++ (void)scanForSupportResources
+{
+ // TODO: Instead of hard-coding sysPath we should use some FindFolder-like API!
+ [RKSupportResourceRegistry scanForSupportResourcesInFolder:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"Support Resources"]];
+ [RKSupportResourceRegistry scanForSupportResourcesInFolder:[NSHomeDirectory() stringByAppendingPathComponent:@"Library/Application Support/ResKnife/Support Resources/"]];
+ [RKSupportResourceRegistry scanForSupportResourcesInFolder:[@"/" stringByAppendingPathComponent:@"Library/Application Support/ResKnife/Support Resources/"]];
+}
+
++ (void)scanForSupportResourcesInFolder:(NSString *)path
+{
+// NSLog(@"Looking for resources in %@", path);
+ NSEnumerator *enumerator = [[[NSFileManager defaultManager] directoryContentsAtPath:path] objectEnumerator];
+ while(NSString *name = [enumerator nextObject])
+ {
+// NSLog(@"Examining %@", name);
+ if([[name pathExtension] isEqualToString:@"rsrc"])
+ [[NSDocumentController sharedDocumentController] openDocumentWithContentsOfFile:[path stringByAppendingPathComponent:name] display:YES];
+ }
+}
+
+@end
diff --git a/Cocoa/Classes/Resource.h b/Cocoa/Classes/Resource.h
index 596e242..6108f19 100644
--- a/Cocoa/Classes/Resource.h
+++ b/Cocoa/Classes/Resource.h
@@ -8,6 +8,7 @@
@description The Resource class fully complies with key-value coding, with the keys @"name", @"type", @"resID", @"attributes", @"data", @"dirty" and @"representedFork" available.
*/
+@class ResourceDocument;
@interface Resource : NSObject
{
@private
diff --git a/Cocoa/Classes/Resource.m b/Cocoa/Classes/Resource.m
index 7c41543..a311e5e 100644
--- a/Cocoa/Classes/Resource.m
+++ b/Cocoa/Classes/Resource.m
@@ -177,7 +177,7 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceDidChangeNotification object:self];
}
-- (NSDocument *)document
+- (ResourceDocument *)document
{
return [Resource documentForResource:self];
}
diff --git a/Cocoa/Classes/ResourceDataSource.mm b/Cocoa/Classes/ResourceDataSource.mm
new file mode 100644
index 0000000..4625bc3
--- /dev/null
+++ b/Cocoa/Classes/ResourceDataSource.mm
@@ -0,0 +1,247 @@
+#import "ResourceDataSource.h"
+#import "ResourceDocument.h"
+#import "Resource.h"
+#import
+
+NSString *DataSourceWillAddResourceNotification = @"DataSourceWillAddResource";
+NSString *DataSourceDidAddResourceNotification = @"DataSourceDidAddResource";
+NSString *DataSourceWillRemoveResourceNotification = @"DataSourceWillRemoveResource";
+NSString *DataSourceDidRemoveResourceNotification = @"DataSourceDidRemoveResource";
+
+extern NSString *RKResourcePboardType;
+
+@implementation ResourceDataSource
+
+- (id)init
+{
+ self = [super init];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceDidChange:) name:ResourceDidChangeNotification object:nil];
+ return self;
+}
+
+- (void)dealloc
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+- (NSWindow *)window
+{
+ return window;
+}
+
+- (NSArray *)resources
+{
+ return resources;
+}
+
+- (void)setResources:(NSMutableArray *)newResources
+{
+ id old = resources;
+ resources = [newResources retain];
+ [old release];
+ [outlineView reloadData];
+}
+
+- (void)addResource:(Resource *)resource
+{
+ NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:self, @"DataSource", resource, @"Resource", nil];
+ [[NSNotificationCenter defaultCenter] postNotificationName:DataSourceWillAddResourceNotification object:dictionary];
+
+ // it seems very inefficient to reload the entire data source when just adding/removing one item
+ // for large resource files, the data source gets reloaded hundreds of times upon load
+ [resources addObject:resource];
+ [outlineView reloadData];
+
+ [[NSNotificationCenter defaultCenter] postNotificationName:DataSourceDidAddResourceNotification object:dictionary];
+ [[document undoManager] registerUndoWithTarget:self selector:@selector(removeResource:) object:resource]; // undo action name set by calling function
+}
+
+- (void)removeResource:(Resource *)resource
+{
+ NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:self, @"DataSource", resource, @"Resource", nil];
+ [[NSNotificationCenter defaultCenter] postNotificationName:DataSourceWillRemoveResourceNotification object:dictionary];
+
+ // see comments in addResource: about inefficiency of reloadData
+ [resources removeObjectIdenticalTo:resource];
+ [outlineView reloadData];
+
+ [[NSNotificationCenter defaultCenter] postNotificationName:DataSourceDidRemoveResourceNotification object:dictionary];
+ [[document undoManager] registerUndoWithTarget:self selector:@selector(addResource:) object:resource]; // NB: I hope the undo manager retains the resource, because it just got deleted :) - undo action name set by calling function
+}
+
+- (void)resourceDidChange:(NSNotification *)notification
+{
+ // reload the data for the changed resource
+ [outlineView reloadItem:[notification object]];
+}
+
+/* Data source protocol implementation */
+
+- (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item
+{
+ #pragma unused(outlineView, item)
+ return [resources objectAtIndex:index];
+}
+
+- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
+{
+ #pragma unused(outlineView, item)
+ return NO;
+}
+
+- (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
+{
+ #pragma unused(outlineView, item)
+ return [resources count];
+}
+
+- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
+{
+ #pragma unused(outlineView)
+ return [item valueForKey:[tableColumn identifier]];
+}
+
+- (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
+{
+ #pragma unused(outlineView)
+ NSString *identifier = [tableColumn identifier];
+ if([identifier isEqualToString:@"resID"])
+ [item setValue:[NSNumber numberWithInt:[object intValue]] forKey:identifier];
+ else [item setValue:object forKey:identifier];
+}
+
+#pragma mark -
+/* ACCESSORS */
+
+- (Resource *)resourceOfType:(NSString *)type andID:(NSNumber *)resID
+{
+ Resource *resource;
+ NSEnumerator *enumerator = [resources objectEnumerator];
+ while(resource = [enumerator nextObject])
+ {
+ if(resID && [[resource resID] isEqualToNumber:resID] && type && [[resource type] isEqualToString:type])
+ return resource;
+ }
+ return nil;
+}
+
+- (Resource *)resourceOfType:(NSString *)type withName:(NSString *)name
+{
+ Resource *resource;
+ NSEnumerator *enumerator = [resources objectEnumerator];
+ while(resource = [enumerator nextObject])
+ {
+ if([[resource name] isEqualToString:name] && [[resource type] isEqualToString:type])
+ return resource;
+ }
+ return nil;
+}
+
+- (NSArray *)allResourcesOfType:(NSString *)type
+{
+ Resource *resource;
+ NSMutableArray *array = [NSMutableArray array];
+ NSEnumerator *enumerator = [resources objectEnumerator];
+ while(resource = [enumerator nextObject])
+ {
+ if([[resource type] isEqualToString:type])
+ [array addObject:resource];
+ }
+ return [NSArray arrayWithArray:array];
+}
+
+/*!
+@method allResourceIDsOfType:
+@discussion Returns an NSArray full of NSNumber* objects containing the IDs of all resources of specified type. Used by uniqueIDForType:.
+@change 2003-08-01 UK Created based on allResourcesOfType:
+*/
+
+- (NSArray*)allResourceIDsOfType:(NSString *)type
+{
+ if(!type || [type isEqualToString:@""])
+ return [NSArray array];
+
+ Resource *resource;
+ NSMutableArray *array = [NSMutableArray array];
+ NSEnumerator *enumerator = [resources objectEnumerator];
+ while(resource = [enumerator nextObject])
+ {
+ if([[resource type] isEqualToString:type])
+ [array addObject:[resource resID]];
+ }
+ return [NSArray arrayWithArray:array];
+}
+
+/*!
+@method uniqueIDForType:
+@discussion Tries to return an unused resource ID for a new resource of specified type. If all IDs are used up (can't really happen, because the resource manager can't take more than 2727 resources per file without crashing, but just in theory...), this will return 128 no matter whether it's used or not.
+@change 2003-08-01 UK Created.
+@change 2003-10-21 NS Changed to obtain initial ID from -[resource defaultIDForType:], so we can vary it on a pre-resource-type basis (like Resourcerer can)
+*/
+
+- (NSNumber *)uniqueIDForType:(NSString *)type
+{
+ short theID = [[self defaultIDForType:type] shortValue];
+ NSArray *array = [self allResourceIDsOfType:type];
+
+ if([array count] <= USHRT_MAX)
+ {
+ while([array containsObject:[NSNumber numberWithShort:theID]])
+ theID++;
+ }
+
+ return [NSNumber numberWithShort: theID];
+}
+
+/*!
+@method defaultIDForType:
+@pending Method should look for resources specifying what the initial ID is for this resource type (e.g. 'vers' resources start at 0)
+*/
+
+- (NSNumber *)defaultIDForType:(NSString *)type
+{
+ short defaultID = 128;
+ return [NSNumber numberWithShort:defaultID];
+}
+
+#pragma mark -
+
+/*!
+@method outlineView:writeItems:toPasteboard:
+@abstract Called at the start of a drag event.
+*/
+- (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pb
+{
+ [pb declareTypes:[NSArray arrayWithObject:RKResourcePboardType] owner:self];
+ [pb setData:[NSArchiver archivedDataWithRootObject:items] forType:RKResourcePboardType];
+ return YES;
+}
+
+/*!
+@method outlineView:validateDrop:proposedItem:proposedChildIndex:
+@abstract Called when the user is hovering with a drop over our outline view.
+*/
+- (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id )info proposedItem:(id)item proposedChildIndex:(int)childIndex
+{
+ if([info draggingSource] != outlineView)
+ {
+ [outlineView setDropItem:nil dropChildIndex:NSOutlineViewDropOnItemIndex];
+ return NSDragOperationCopy;
+ }
+ else return NSDragOperationNone;
+}
+
+/*!
+@method outlineView:acceptDrop:item:childIndex:
+@abstract Called when the user drops something on our outline view.
+*/
+- (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id )info item:(id)targetItem childIndex:(int)childIndex
+{
+ NSPasteboard *pb = [info draggingPasteboard];
+ if([pb availableTypeFromArray:[NSArray arrayWithObject:RKResourcePboardType]])
+ [document pasteResources:[NSUnarchiver unarchiveObjectWithData:[pb dataForType:RKResourcePboardType]]];
+ return YES;
+}
+
+@end
diff --git a/Cocoa/Classes/ResourceDocument.mm b/Cocoa/Classes/ResourceDocument.mm
new file mode 100644
index 0000000..1a36afe
--- /dev/null
+++ b/Cocoa/Classes/ResourceDocument.mm
@@ -0,0 +1,1226 @@
+#import "ResourceDocument.h"
+#import "ResourceDataSource.h"
+#import "ResourceNameCell.h"
+#import "Resource.h"
+#import "ApplicationDelegate.h"
+#import "OpenPanelDelegate.h"
+#import "OutlineViewDelegate.h"
+#import "InfoWindowController.h"
+#import "PrefsWindowController.h"
+#import "CreateResourceSheetController.h"
+#import "Categories.h"
+#import "../Categories/NSString-FSSpec.h"
+#import "../Categories/NSOutlineView-SelectedItems.h"
+
+#import "../Plug-Ins/ResKnifePluginProtocol.h"
+#import "RKEditorRegistry.h"
+
+
+NSString *DocumentInfoWillChangeNotification = @"DocumentInfoWillChangeNotification";
+NSString *DocumentInfoDidChangeNotification = @"DocumentInfoDidChangeNotification";
+extern NSString *RKResourcePboardType;
+
+@implementation ResourceDocument
+
+- (id)init
+{
+ self = [super init];
+ if(!self) return nil;
+ toolbarItems = [[NSMutableDictionary alloc] init];
+ resources = [[NSMutableArray alloc] init];
+ fork = nil;
+ creator = [[@"ResK" dataUsingEncoding:NSMacOSRomanStringEncoding] retain]; // should I be calling -setCreator & -setType here instead?
+ type = [[@"rsrc" dataUsingEncoding:NSMacOSRomanStringEncoding] retain];
+ return self;
+}
+
+- (void)dealloc
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ if(fork) DisposePtr((Ptr) fork);
+ [resources release];
+ [toolbarItems release];
+ [type release];
+ [creator release];
+ [super dealloc];
+}
+
+#pragma mark -
+#pragma mark File Management
+
+/*!
+@method readFromFile:ofType:
+@abstract Open the specified file and read its resources.
+@description Open the specified file and read its resources. This first tries to load the resources from the res fork, and failing that tries the data fork.
+@author Nicholas Shanks
+@change 2003-11-08 NS: Now handles opening user-selected forks.
+*/
+
+-(BOOL)readFromFile:(NSString *)fileName ofType:(NSString *)fileKind
+{
+ BOOL succeeded = NO;
+ OSStatus error = noErr;
+ FSRef *fileRef = (FSRef *) NewPtrClear(sizeof(FSRef));
+ SInt16 fileRefNum = 0;
+ OpenPanelDelegate *openPanelDelegate = [(ApplicationDelegate *)[NSApp delegate] openPanelDelegate];
+
+ // bug: need to handle error better here
+ error = FSPathMakeRef((const UInt8 *)[fileName fileSystemRepresentation], fileRef, nil);
+ if(error) return NO;
+
+ // find out which fork to parse
+ if(NSAppKitVersionNumber < 700.0 || ![openPanelDelegate readOpenPanelForFork])
+ {
+ // display second dialog to ask user to select a fork, pre-10.3 or if open command did not come via the open dialog
+
+ // bug: unimplemented - always tells app to try resource fork first
+ fork = (HFSUniStr255 *) NewPtrClear(sizeof(HFSUniStr255));
+ error = FSGetResourceForkName(fork);
+ if(error) return NO;
+ }
+ else
+ {
+ // get selected fork from open panel, 10.3+
+ int row = [[openPanelDelegate forkTableView] selectedRow];
+ NSString *selectedFork = [(NSDictionary *)[[openPanelDelegate forks] objectAtIndex:row] valueForKey:@"forkname"];
+ fork = (HFSUniStr255 *) NewPtrClear(sizeof(HFSUniStr255));
+ fork->length = ([selectedFork length] < 255)? [selectedFork length]:255;
+ if(fork->length > 0)
+ [selectedFork getCharacters:fork->unicode range:NSMakeRange(0,fork->length)];
+ else fork->unicode[0] = 0;
+
+ // clear so next document doesn't get confused
+ [openPanelDelegate setReadOpenPanelForFork:NO];
+ }
+
+ NSArray *forks = [(ApplicationDelegate *)[NSApp delegate] forksForFile:fileRef];
+
+ // attempt to open fork user selected as a resource map
+ SetResLoad(false); // don't load "preload" resources
+ error = FSOpenResourceFile(fileRef, fork->length, (UniChar *) &fork->unicode, fsRdPerm, &fileRefNum);
+ if(error || !fileRefNum)
+ {
+ // if opening the user-selected fork fails, try to open resource fork instead
+ error = FSGetResourceForkName(fork);
+ if(error) return NO;
+/* HFSUniStr255 *rfork;
+ error = FSGetResourceForkName(rfork);
+ if(error) return NO;
+
+ bool checkFork = true;
+ if(FSCreateStringFromHFSUniStr) // 10.4 only
+ {
+ if(CFStringCompare(FSCreateStringFromHFSUniStr(NULL, fork), FSCreateStringFromHFSUniStr(NULL, rfork), 0) == NSOrderedSame)
+ checkFork = false; // skip checking resource fork if it's the one the user chose
+ else fork = rfork;
+ }
+ if(checkFork)
+*/ error = FSOpenResourceFile(fileRef, fork->length, (UniChar *) &fork->unicode, fsRdPerm, &fileRefNum);
+ if(error || !fileRefNum)
+ {
+ // if opening the resource fork fails, try to open data fork instead
+ error = FSGetDataForkName(fork);
+ if(error) return NO;
+ error = FSOpenResourceFile(fileRef, fork->length, (UniChar *) &fork->unicode, fsRdPerm, &fileRefNum);
+ if(error || !fileRefNum)
+ {
+ // bug: should check fork the user selected is empty before trying data fork
+ NSNumber *fAlloc = [[forks firstObjectReturningValue:[NSString stringWithCharacters:fork->unicode length:fork->length] forKey:@"forkname"] valueForKey:@"forkallocation"];
+ if([fAlloc unsignedLongLongValue] > 0)
+ {
+ // data fork is not empty, check resource fork
+ error = FSGetResourceForkName(fork);
+ if(error) return NO;
+ fAlloc = [[forks firstObjectReturningValue:[NSString stringWithCharacters:fork->unicode length:fork->length] forKey:@"forkname"] valueForKey:@"forkallocation"];
+ if([fAlloc unsignedLongLongValue] > 0)
+ {
+ // resource fork is not empty either, give up (ask user for a fork?)
+ NSLog(@"Could not find existing map nor create a new map in either the data or resource forks! Aborting.");
+ return NO;
+ }
+ }
+
+ // note that map needs initalising on first save
+ _createFork = YES;
+ }
+ }
+ }
+ SetResLoad(true); // restore resource loading as soon as is possible
+
+ if(!_createFork)
+ {
+ // disable undos during resource creation and setting of the creator and type
+ [[self undoManager] disableUndoRegistration];
+
+ // then read resources from the selected fork
+ succeeded = [self readResourceMap:fileRefNum];
+
+ // get creator and type
+ FSCatalogInfo info;
+ error = FSGetCatalogInfo(fileRef, kFSCatInfoFinderInfo, &info, nil, nil, nil);
+ if(!error)
+ {
+ [self setType:[NSData dataWithBytes:&((FileInfo *)info.finderInfo)->fileType length:4]];
+ [self setCreator:[NSData dataWithBytes:&((FileInfo *)info.finderInfo)->fileCreator length:4]];
+ }
+
+ // restore undos
+ [[self undoManager] enableUndoRegistration];
+ }
+ else succeeded = YES;
+
+ // now read all other forks as streams
+ NSEnumerator *forkEnumerator = [forks objectEnumerator];
+ NSString *selectedFork = [NSString stringWithCharacters:fork->unicode length:fork->length];
+ while(NSString *forkName = [[forkEnumerator nextObject] valueForKey:@"forkname"])
+ {
+ // check current fork is not the fork we're going to parse
+ if(![forkName isEqualToString:selectedFork])
+ [self readFork:forkName asStreamFromFile:fileRef];
+ }
+
+ // tidy up loose ends
+ if(fileRefNum) FSClose(fileRefNum);
+ DisposePtr((Ptr) fileRef);
+ return succeeded;
+}
+
+/*!
+@method readFork:asStreamFromFile:
+@author Nicholas Shanks
+@change 2003-11-08 NGS: Now handles opening user-selected forks.
+@description Note: there is a 2 GB limit to the size of forks that can be read in due to FSReaadFork() taking a 32-bit buffer length value.
+*/
+
+- (BOOL)readFork:(NSString *)forkName asStreamFromFile:(FSRef *)fileRef
+{
+ if(!fileRef) return NO;
+
+ /* NTFS Note: When running SFM (Services for Macintosh) a Windows NT-based system (including 2000 & XP) serving NTFS-formatted drives stores Mac resource forks in a stream named "AFP_Resource". The finder info/attributes are stored in a stream called "AFP_AfpInfo". The default data fork stream is called "$DATA" and any of these can be accessed thus: "c:\filename.txt:forkname". Finder comments are stored in a stream called "Comments".
+ As a result, ResKnife prohibits creation of forks with the following names: "" (empty string, Mac data fork name),
+ "$DATA" (NTFS data fork name),
+ "AFP_Resource", "AFP_AfpInfo" and "Comments".
+ It is perfectly legal in ResKnife to read in forks of these names when accessing a shared NTFS drive via SMB. The server does not need to be running SFM since the file requests will appear to be coming from a PC. If the files are accessed via AFP on a server running SFM, SFM will automatically convert the files (and truncate the name to 31 chars). */
+
+
+ // translate NSString into HFSUniStr255 -- in 10.4 this can be done with FSGetHFSUniStrFromString
+ HFSUniStr255 uniForkName = { 0 };
+ uniForkName.length = ([forkName length] < 255)? [forkName length]:255;
+ if(uniForkName.length > 0)
+ [forkName getCharacters:uniForkName.unicode range:NSMakeRange(0, uniForkName.length)];
+ else uniForkName.unicode[0] = 0;
+
+ // get fork length and create empty buffer, bug: only sizeof(size_t) bytes long
+ ByteCount forkLength = (ByteCount) [[[[(ApplicationDelegate *)[NSApp delegate] forksForFile:fileRef] firstObjectReturningValue:forkName forKey:@"forkname"] valueForKey:@"forksize"] unsignedLongValue];
+ void *buffer = malloc(forkLength);
+ if(!buffer) return NO;
+
+ // read fork contents into buffer, bug: assumes no errors
+ SInt16 forkRefNum;
+ FSOpenFork(fileRef, uniForkName.length, uniForkName.unicode, fsRdPerm, &forkRefNum);
+ FSReadFork(forkRefNum, fsFromStart, 0, forkLength, buffer, &forkLength);
+ FSCloseFork(forkRefNum);
+
+ // create data
+ NSData *data = [NSData dataWithBytesNoCopy:buffer length:forkLength freeWhenDone:YES];
+ if(!data) return NO;
+
+ // create resource
+ Resource *resource = [Resource resourceOfType:@"" andID:0 withName:forkName andAttributes:0 data:data];
+ if(!resource) return NO;
+
+ // customise fork name for default data & resource forks - bug: this should really be in resource data source!!
+ HFSUniStr255 resourceForkName;
+ OSErr error = FSGetResourceForkName(&resourceForkName);
+ if(!error && [[resource name] isEqualToString:@""]) // bug: should use FSGetDataForkName()
+ [resource _setName:NSLocalizedString(@"Data Fork", nil)];
+ else if(!error && [[resource name] isEqualToString:[NSString stringWithCharacters:resourceForkName.unicode length:resourceForkName.length]])
+ [resource _setName:NSLocalizedString(@"Resource Fork", nil)];
+
+ [resource setRepresentedFork:forkName];
+ [resources addObject:resource];
+ return YES;
+}
+
+-(BOOL)readResourceMap:(SInt16)fileRefNum
+{
+ OSStatus error = noErr;
+ SInt16 oldResFile = CurResFile();
+ UseResFile(fileRefNum);
+
+ for(unsigned short i = 1; i <= Count1Types(); i++)
+ {
+ ResType resType;
+ Get1IndType(&resType, i);
+ ResType swappedType = EndianS32_NtoB(resType); // Swapped type for use as string (types are treated as numbers by the resource manager and swapped on Intel).
+ unsigned short n = Count1Resources(resType);
+ for(unsigned short j = 1; j <= n; j++)
+ {
+ Handle resourceHandle = Get1IndResource(resType, j);
+ error = ResError();
+ if(error != noErr)
+ {
+ NSLog(@"Error %d reading resource map...", error);
+ UseResFile(oldResFile);
+ return NO;
+ }
+
+ Str255 nameStr;
+ short resIDShort;
+ GetResInfo(resourceHandle, &resIDShort, &resType, nameStr);
+ long sizeLong = GetResourceSizeOnDisk(resourceHandle);
+ short attrsShort = GetResAttrs(resourceHandle);
+ HLockHi(resourceHandle);
+
+ // cool: "The advantage of obtaining a methodŐs implementation and calling it as a function is that you can invoke the implementation multiple times within a loop, or similar C construct, without the overhead of Objective-C messaging."
+
+ // create the resource & add it to the array
+ NSString *name = [[NSString alloc] initWithBytes:&nameStr[1] length:nameStr[0] encoding:NSMacOSRomanStringEncoding];
+ NSString *type = [[NSString alloc] initWithBytes:(char *) &swappedType length:4 encoding:NSMacOSRomanStringEncoding];
+ NSNumber *resID = [NSNumber numberWithShort:resIDShort];
+ NSNumber *attributes = [NSNumber numberWithShort:attrsShort];
+ NSData *data = [NSData dataWithBytes:*resourceHandle length:sizeLong];
+ Resource *resource = [Resource resourceOfType:type andID:resID withName:name andAttributes:attributes data:data];
+ [resources addObject:resource]; // array retains resource
+ [name release];
+ [type release];
+
+ HUnlock(resourceHandle);
+ ReleaseResource(resourceHandle);
+ }
+ }
+
+ // save resource map and clean up
+ UseResFile(oldResFile);
+ return YES;
+}
+
+/*!
+@pending Uli's changed this routine - see what I had and unify the two
+@pending Doesn't write correct type/creator info - always ResKnife's!
+*/
+
+- (BOOL)writeToFile:(NSString *)fileName ofType:(NSString *)type
+{
+ OSStatus error = noErr;
+ SInt16 fileRefNum = 0;
+ FSRef *parentRef = (FSRef *) NewPtrClear(sizeof(FSRef));
+ FSRef *fileRef = (FSRef *) NewPtrClear(sizeof(FSRef));
+
+ // create and open file for writing
+ // bug: doesn't set the cat info to the same as the old file
+ unichar *uniname = (unichar *) NewPtrClear(sizeof(unichar) *256);
+ [[fileName lastPathComponent] getCharacters:uniname];
+ error = FSPathMakeRef((const UInt8 *)[[fileName stringByDeletingLastPathComponent] UTF8String], parentRef, nil);
+ if(fork)
+ error = FSCreateResourceFile(parentRef, [[fileName lastPathComponent] length], (UniChar *) uniname, kFSCatInfoNone, NULL, fork->length, (UniChar *) &fork->unicode, fileRef, NULL);
+ else error = FSCreateResourceFile(parentRef, [[fileName lastPathComponent] length], (UniChar *) uniname, kFSCatInfoNone, NULL, 0, NULL, fileRef, NULL);
+
+ // write any data streams to file
+ BOOL succeeded = [self writeForkStreamsToFile:fileName];
+// FSRef *fileRef = [fileName createFSRef];
+
+/* error = FSPathMakeRef((const UInt8 *)[fileName UTF8String], fileRef, nil);
+ if(_createFork)
+ {
+ error = FSCreateResourceFork(fileRef, fork->length, (UniChar *) &fork->unicode, 0);
+ _createFork = NO;
+ }
+*/
+ if(!error)
+ {
+ // set creator & type
+ // bug: due to a bug in AppKit, the temporary file that we are writing to (in /var/tmp, managed by NSDocument) does not get it's creator code copied over to the new document (it sets the new document's to nil). this timer sets the creator code after we have returned to the main loop and the buggy Apple code has been bypassed.
+ [NSTimer scheduledTimerWithTimeInterval:0.0 target:self selector:@selector(setTypeCreatorAfterSave:) userInfo:nil repeats:NO];
+
+ // open fork as resource map
+ if(fork)
+ error = FSOpenResourceFile(fileRef, fork->length, (UniChar *) &fork->unicode, fsWrPerm, &fileRefNum);
+ else error = FSOpenResourceFile(fileRef, 0, NULL, fsWrPerm, &fileRefNum);
+ }
+// else NSLog(@"error creating resource fork. (error=%d, spec=%d, ref=%d, parent=%d)", error, fileSpec, fileRef, parentRef);
+ else NSLog(@"error creating resource fork. (error=%d, ref=%d)", error, fileRef);
+
+ // write resource array to file
+ if(fileRefNum && !error)
+ succeeded = [self writeResourceMap:fileRefNum];
+
+ // tidy up loose ends
+ if(fileRefNum) FSClose(fileRefNum);
+ DisposePtr((Ptr) fileRef);
+
+ // update info window
+ [[InfoWindowController sharedInfoWindowController] updateInfoWindow];
+
+ return succeeded;
+}
+
+- (BOOL)writeForkStreamsToFile:(NSString *)fileName
+{
+ // try and get an FSRef
+ OSStatus error;
+ FSRef *fileRef = [fileName createFSRef], *parentRef = nil;
+ if(!fileRef)
+ {
+ parentRef = (FSRef *) NewPtrClear(sizeof(FSRef));
+ fileRef = (FSRef *) NewPtrClear(sizeof(FSRef));
+ unichar *uniname = (unichar *) NewPtrClear(sizeof(unichar) *256);
+ [[fileName lastPathComponent] getCharacters:uniname];
+ error = FSPathMakeRef((const UInt8 *)[[fileName stringByDeletingLastPathComponent] UTF8String], parentRef, nil);
+ if(error) return NO;
+ error = FSCreateFileUnicode(parentRef, 0, NULL, kFSCatInfoNone, NULL, fileRef, NULL);
+ if(error || !fileRef) return NO;
+ }
+
+ NSEnumerator *enumerator = [resources objectEnumerator];
+ while(Resource *resource = [enumerator nextObject])
+ {
+ // if the resource object represents an actual resource, skip it
+ if([resource representedFork] == nil) continue;
+ unichar *uniname = (unichar *) NewPtrClear(sizeof(unichar) *256);
+ [[resource representedFork] getCharacters:uniname];
+ SInt16 forkRefNum = 0;
+ error = FSOpenFork(fileRef, [[resource representedFork] length], (UniChar *) uniname, fsWrPerm, &forkRefNum);
+ if(!error && forkRefNum)
+ error = FSWriteFork(forkRefNum, fsFromStart, 0, [[resource data] length], [[resource data] bytes], NULL);
+ if(forkRefNum) FSClose(forkRefNum);
+ }
+ DisposePtr((Ptr) fileRef);
+ return YES;
+}
+
+/*!
+@method writeResourceMap:
+@abstract Writes all resources (except the ones representing other forks of the file) to the specified resource file.
+*/
+
+- (BOOL)writeResourceMap:(SInt16)fileRefNum
+{
+ // make the resource file current
+ OSStatus error = noErr;
+ SInt16 oldResFile = CurResFile();
+ UseResFile(fileRefNum);
+
+ // loop over all our resources
+ NSEnumerator *enumerator = [resources objectEnumerator];
+ while(Resource *resource = [enumerator nextObject])
+ {
+ Str255 nameStr;
+ char resType[5]; // includes null char for getCString:
+ short resIDShort;
+ short attrsShort;
+ Handle resourceHandle;
+
+ // if the resource represents another fork in the file, skip it
+ if([resource representedFork] != nil) continue;
+
+ resIDShort = [[resource resID] shortValue];
+ attrsShort = [[resource attributes] shortValue];
+ resourceHandle = NewHandleClear([[resource data] length]);
+
+ // convert unicode name to pascal string
+ nameStr[0] = [[resource name] lengthOfBytesUsingEncoding:NSMacOSRomanStringEncoding];
+ BlockMoveData([[resource name] cStringUsingEncoding:NSMacOSRomanStringEncoding], &nameStr[1], nameStr[0]);
+
+ // convert type string to ResType
+ [[resource type] getCString:resType maxLength:4];
+
+ // convert NSData to resource handle
+ HLockHi(resourceHandle);
+ [[resource data] getBytes:*resourceHandle];
+ HUnlock(resourceHandle);
+
+ // now that everything's converted, tell the resource manager we want to create this resource
+ AddResource(resourceHandle, *(ResType *)resType, resIDShort, nameStr);
+ if(ResError() == addResFailed)
+ {
+ NSLog(@"*Saving failed*; could not add resource ID %@ of type %@ to file.", [resource resID], [resource type]);
+ DisposeHandle(resourceHandle);
+ error = addResFailed;
+ }
+ else
+ {
+// NSLog(@"Added resource ID %@ of type %@ to file.", [resource resID], [resource type]);
+ SetResAttrs(resourceHandle, attrsShort);
+ ChangedResource(resourceHandle);
+ // the resourceHandle memory is disposed of when calling CloseResFile() for the file to which the resource has been added
+ }
+ }
+
+ // update the file on disk
+ UpdateResFile(fileRefNum);
+
+ // restore original resource file
+ UseResFile(oldResFile);
+ return error? NO:YES;
+}
+
+- (void)setTypeCreatorAfterSave:(id)userInfo
+{
+ FInfo finderInfo;
+ FSRef *fileRef = (FSRef *) NewPtrClear(sizeof(FSRef));
+ FSSpec *fileSpec = (FSSpec *) NewPtrClear(sizeof(FSSpec));
+ OSStatus error = FSPathMakeRef((const UInt8 *)[[self fileName] UTF8String], fileRef, nil);
+ if(!error)
+ {
+ error = FSGetCatalogInfo(fileRef, kFSCatInfoNone, NULL, NULL, fileSpec, NULL);
+ if(!error)
+ {
+ error = FSpGetFInfo(fileSpec, &finderInfo);
+ if(!error)
+ {
+ [[self type] getBytes:&finderInfo.fdType length:4];
+ [[self creator] getBytes:&finderInfo.fdCreator length:4];
+// NSLog(@"setting finder info to type: %X; creator: %X", finderInfo.fdType, finderInfo.fdCreator);
+ error = FSpSetFInfo(fileSpec, &finderInfo);
+ FSpGetFInfo(fileSpec, &finderInfo);
+// NSLog(@"finder info got set to type: %X; creator: %X", finderInfo.fdType, finderInfo.fdCreator);
+ }
+ else NSLog(@"error getting Finder info. (error=%d, spec=%d, ref=%d)", error, fileSpec, fileRef);
+ }
+ else NSLog(@"error converting fsref to fsspec. (error=%d, spec=%d, ref=%d)", error, fileSpec, fileRef);
+ }
+ else NSLog(@"error making fsref from file path. (error=%d, ref=%d, path=%@)", error, fileRef, [self fileName]);
+}
+
+#pragma mark -
+#pragma mark Export to File
+
+/*!
+@method exportResources:
+@author Nicholas Shanks
+@created 24 October 2003
+@pending note that this method will cause a cascade of sheets to be displayed for each resource being exported! v.bad needs fixing
+*/
+
+- (IBAction)exportResources:(id)sender
+{
+ Resource *current;
+ NSEnumerator *enumerator = [[outlineView selectedItems] objectEnumerator];
+ while(current = [enumerator nextObject])
+ {
+ [self exportResource:current];
+ }
+}
+
+/*!
+@method exportResource:
+@author Uli Kusterer
+@change 2003-10-24 NGS: moved IBAction target to exportResources: above, renamed this method
+*/
+
+#warning Note to Uli: how about changing the selector that the plug should implement to -(BOOL)dataForFileExport:(NSData **)fileData ofType:(NSString **)fileType. This is basically a concatenation of the two methods you came up with, but can allow the host app to specify a preferred file type (e.g. EPS) to a plug (say the PICT plug) and if the plug can't return data in that format, that's OK, it just returns the fileType of the associated data anyway. I would also recommend adding a plug method called something like availableTypesForFileExport: which returns a dictionary of file extensions and human-readable names (names should be overridden by system default names for that extension if present) that the plug can export data into, useful for say populating a pop-up menu in the export dialog.
+
+- (void)exportResource:(Resource *)resource
+{
+ Class editorClass = [[RKEditorRegistry defaultRegistry] editorForType:[resource type]];
+ NSData *exportData = [resource data];
+ NSString *extension = [resource type];
+ NSSavePanel *panel;
+ NSString *filename;
+
+ if([editorClass respondsToSelector:@selector(dataForFileExport:)])
+ exportData = [editorClass dataForFileExport:resource];
+
+ if([editorClass respondsToSelector:@selector(filenameExtensionForFileExport:)])
+ extension = [editorClass filenameExtensionForFileExport:resource];
+
+ panel = [NSSavePanel savePanel];
+ filename = [[resource name] stringByAppendingFormat:@".%@", extension];
+ [panel beginSheetForDirectory:nil file:filename modalForWindow:mainWindow modalDelegate:self didEndSelector:@selector(exportPanelDidEnd:returnCode:contextInfo:) contextInfo:[exportData retain]];
+}
+
+- (void)exportPanelDidEnd:(NSSavePanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
+{
+ NSData *data = (NSData *) contextInfo;
+ [data autorelease];
+
+ if(returnCode == NSOKButton)
+ [data writeToFile:[sheet filename] atomically:YES];
+}
+
+#pragma mark -
+#pragma mark Window Management
+
+- (NSString *)windowNibName
+{
+ return @"ResourceDocument";
+}
+
+/* This is not used, just here for reference in case I need it in the future
+
+- (void)makeWindowControllers
+{
+ ResourceWindowController *resourceController = [[ResourceWindowController allocWithZone:[self zone]] initWithWindowNibName:@"ResourceDocument"];
+ [self addWindowController:resourceController];
+}*/
+
+- (void)windowControllerDidLoadNib:(NSWindowController *)controller
+{
+ [super windowControllerDidLoadNib:controller];
+ [self setupToolbar:controller];
+
+ { // set up first column in outline view to display images as well as text
+ ResourceNameCell *resourceNameCell = [[[ResourceNameCell alloc] init] autorelease];
+ [resourceNameCell setEditable:YES];
+ [[outlineView tableColumnWithIdentifier:@"name"] setDataCell:resourceNameCell];
+// NSLog(@"Changed data cell");
+ }
+
+ // set outline view's inter-cell spacing to zero to avoid getting gaps between blue bits
+ [outlineView setIntercellSpacing:NSMakeSize(0,0)];
+ [outlineView setTarget:self];
+ [outlineView setDoubleAction:@selector(openResources:)];
+ [outlineView setVerticalMotionCanBeginDrag:YES];
+ [outlineView registerForDraggedTypes:[NSArray arrayWithObjects:RKResourcePboardType, NSStringPboardType, NSFilenamesPboardType, nil]];
+
+ // register for resource will change notifications (for undo management)
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceNameWillChange:) name:ResourceNameWillChangeNotification object:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceIDWillChange:) name:ResourceIDWillChangeNotification object:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceTypeWillChange:) name:ResourceTypeWillChangeNotification object:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceAttributesWillChange:) name:ResourceAttributesWillChangeNotification object:nil];
+
+// [[controller window] setResizeIncrements:NSMakeSize(1,18)];
+ [dataSource setResources:resources];
+}
+
+- (void)printShowingPrintPanel:(BOOL)flag
+{
+ NSPrintOperation *printOperation = [NSPrintOperation printOperationWithView:[mainWindow contentView]];
+ [printOperation runOperationModalForWindow:mainWindow delegate:self didRunSelector:@selector(printOperationDidRun:success:contextInfo:) contextInfo:nil];
+}
+
+- (void)printOperationDidRun:(NSPrintOperation *)printOperation success:(BOOL)success contextInfo:(void *)contextInfo
+{
+ if(!success) NSLog(@"Printing Failed!");
+}
+
+- (BOOL)keepBackupFile
+{
+ return [[NSUserDefaults standardUserDefaults] boolForKey:@"PreserveBackups"];
+}
+
+- (BOOL)validateMenuItem:(NSMenuItem *)item
+{
+ int selectedRows = [outlineView numberOfSelectedRows];
+ Resource *resource = (Resource *) [outlineView selectedItem];
+
+ // file menu
+ if([item action] == @selector(saveDocument:)) return [self isDocumentEdited];
+
+ // edit menu
+ else if([item action] == @selector(clear:)) return selectedRows > 0;
+ else if([item action] == @selector(selectAll:)) return [outlineView numberOfRows] > 0;
+ else if([item action] == @selector(deselectAll:)) return selectedRows > 0;
+
+ // resource menu
+ else if([item action] == @selector(openResources:)) return selectedRows > 0;
+ else if([item action] == @selector(openResourcesInTemplate:)) return selectedRows > 0;
+ else if([item action] == @selector(openResourcesWithOtherTemplate:)) return selectedRows > 0;
+ else if([item action] == @selector(openResourcesAsHex:)) return selectedRows > 0;
+ else if([item action] == @selector(exportResourceToImageFile:))
+ {
+ if(selectedRows < 1) return NO;
+ Class editorClass = [[RKEditorRegistry defaultRegistry] editorForType:[resource type]];
+ return [editorClass respondsToSelector:@selector(imageForImageFileExport:)];
+ }
+ else if([item action] == @selector(playSound:)) return selectedRows == 1 && [[resource type] isEqualToString:@"snd "];
+ else if([item action] == @selector(revertResourceToSaved:)) return selectedRows == 1 && [resource isDirty];
+ else return [super validateMenuItem:item];
+}
+
+#pragma mark -
+#pragma mark Toolbar Management
+
+static NSString *RKToolbarIdentifier = @"com.nickshanks.resknife.toolbar";
+static NSString *RKCreateItemIdentifier = @"com.nickshanks.resknife.toolbar.create";
+static NSString *RKDeleteItemIdentifier = @"com.nickshanks.resknife.toolbar.delete";
+static NSString *RKEditItemIdentifier = @"com.nickshanks.resknife.toolbar.edit";
+static NSString *RKEditHexItemIdentifier = @"com.nickshanks.resknife.toolbar.edithex";
+static NSString *RKSaveItemIdentifier = @"com.nickshanks.resknife.toolbar.save";
+static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.showinfo";
+static NSString *RKExportItemIdentifier = @"com.nickshanks.resknife.toolbar.export";
+
+- (void)setupToolbar:(NSWindowController *)windowController
+{
+ /* This routine should become invalid once toolbars are integrated into nib files */
+
+ NSToolbarItem *item;
+ [toolbarItems removeAllObjects]; // just in case this method is called more than once per document (which it shouldn't be!)
+
+ item = [[NSToolbarItem alloc] initWithItemIdentifier:RKCreateItemIdentifier];
+ [item autorelease];
+ [item setLabel:NSLocalizedString(@"Create", nil)];
+ [item setPaletteLabel:NSLocalizedString(@"Create", nil)];
+ [item setToolTip:NSLocalizedString(@"Create New Resource", nil)];
+ [item setImage:[NSImage imageNamed:@"Create"]];
+ [item setTarget:self];
+ [item setAction:@selector(showCreateResourceSheet:)];
+ [toolbarItems setObject:item forKey:RKCreateItemIdentifier];
+
+ item = [[NSToolbarItem alloc] initWithItemIdentifier:RKDeleteItemIdentifier];
+ [item autorelease];
+ [item setLabel:NSLocalizedString(@"Delete", nil)];
+ [item setPaletteLabel:NSLocalizedString(@"Delete", nil)];
+ [item setToolTip:NSLocalizedString(@"Delete Selected Resource", nil)];
+ [item setImage:[NSImage imageNamed:@"Delete"]];
+ [item setTarget:self];
+ [item setAction:@selector(clear:)];
+ [toolbarItems setObject:item forKey:RKDeleteItemIdentifier];
+
+ item = [[NSToolbarItem alloc] initWithItemIdentifier:RKEditItemIdentifier];
+ [item autorelease];
+ [item setLabel:NSLocalizedString(@"Edit", nil)];
+ [item setPaletteLabel:NSLocalizedString(@"Edit", nil)];
+ [item setToolTip:NSLocalizedString(@"Edit Resource In Default Editor", nil)];
+ [item setImage:[NSImage imageNamed:@"Edit"]];
+ [item setTarget:self];
+ [item setAction:@selector(openResources:)];
+ [toolbarItems setObject:item forKey:RKEditItemIdentifier];
+
+ item = [[NSToolbarItem alloc] initWithItemIdentifier:RKEditHexItemIdentifier];
+ [item autorelease];
+ [item setLabel:NSLocalizedString(@"Edit Hex", nil)];
+ [item setPaletteLabel:NSLocalizedString(@"Edit Hex", nil)];
+ [item setToolTip:NSLocalizedString(@"Edit Resource As Hexadecimal", nil)];
+ [item setImage:[NSImage imageNamed:@"Edit Hex"]];
+ [item setTarget:self];
+ [item setAction:@selector(openResourcesAsHex:)];
+ [toolbarItems setObject:item forKey:RKEditHexItemIdentifier];
+
+ item = [[NSToolbarItem alloc] initWithItemIdentifier:RKSaveItemIdentifier];
+ [item autorelease];
+ [item setLabel:NSLocalizedString(@"Save", nil)];
+ [item setPaletteLabel:NSLocalizedString(@"Save", nil)];
+ [item setToolTip:[NSString stringWithFormat:NSLocalizedString(@"Save To %@ Fork", nil), !fork? NSLocalizedString(@"Data", nil) : NSLocalizedString(@"Resource", nil)]];
+ [item setImage:[NSImage imageNamed:@"Save"]];
+ [item setTarget:self];
+ [item setAction:@selector(saveDocument:)];
+ [toolbarItems setObject:item forKey:RKSaveItemIdentifier];
+
+ item = [[NSToolbarItem alloc] initWithItemIdentifier:RKShowInfoItemIdentifier];
+ [item autorelease];
+ [item setLabel:NSLocalizedString(@"Show Info", nil)];
+ [item setPaletteLabel:NSLocalizedString(@"Show Info", nil)];
+ [item setToolTip:NSLocalizedString(@"Show Resource Information Window", nil)];
+ [item setImage:[NSImage imageNamed:@"Show Info"]];
+ [item setTarget:[NSApp delegate]];
+ [item setAction:@selector(showInfo:)];
+ [toolbarItems setObject:item forKey:RKShowInfoItemIdentifier];
+
+ item = [[NSToolbarItem alloc] initWithItemIdentifier:RKExportItemIdentifier];
+ [item autorelease];
+ [item setLabel:NSLocalizedString(@"Export Data", nil)];
+ [item setPaletteLabel:NSLocalizedString(@"Export Resource Data", nil)];
+ [item setToolTip:NSLocalizedString(@"Export the resource's data to a file", nil)];
+ [item setImage:[NSImage imageNamed:@"Export"]];
+ [item setTarget:self];
+ [item setAction:@selector(exportResources:)];
+ [toolbarItems setObject:item forKey:RKExportItemIdentifier];
+
+ if([windowController window] == mainWindow)
+ {
+ NSToolbar *toolbar = [[[NSToolbar alloc] initWithIdentifier:RKToolbarIdentifier] autorelease];
+
+ // set toolbar properties
+ [toolbar setVisible:YES];
+ [toolbar setAutosavesConfiguration:YES];
+ [toolbar setAllowsUserCustomization:YES];
+ [toolbar setDisplayMode:NSToolbarDisplayModeDefault];
+
+ // attach toolbar to window
+ [toolbar setDelegate:self];
+ [mainWindow setToolbar:toolbar];
+ }
+}
+
+- (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag
+{
+ return [toolbarItems objectForKey:itemIdentifier];
+}
+
+- (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar
+{
+ return [NSArray arrayWithObjects:RKCreateItemIdentifier, RKShowInfoItemIdentifier, RKDeleteItemIdentifier, NSToolbarSeparatorItemIdentifier, RKEditItemIdentifier, RKEditHexItemIdentifier, NSToolbarSeparatorItemIdentifier, RKSaveItemIdentifier, NSToolbarPrintItemIdentifier, NSToolbarFlexibleSpaceItemIdentifier, NSToolbarCustomizeToolbarItemIdentifier, nil];
+}
+
+- (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar
+{
+ return [NSArray arrayWithObjects:RKCreateItemIdentifier, RKDeleteItemIdentifier, RKEditItemIdentifier, RKEditHexItemIdentifier, RKSaveItemIdentifier, RKExportItemIdentifier, RKShowInfoItemIdentifier, NSToolbarPrintItemIdentifier, NSToolbarCustomizeToolbarItemIdentifier, NSToolbarFlexibleSpaceItemIdentifier, NSToolbarSpaceItemIdentifier, NSToolbarSeparatorItemIdentifier, nil];
+}
+
+- (BOOL)validateToolbarItem:(NSToolbarItem *)item
+{
+ BOOL valid = NO;
+ int selectedRows = [outlineView numberOfSelectedRows];
+ NSString *identifier = [item itemIdentifier];
+
+ if([identifier isEqualToString:RKCreateItemIdentifier]) valid = YES;
+ else if([identifier isEqualToString:RKDeleteItemIdentifier]) valid = selectedRows > 0;
+ else if([identifier isEqualToString:RKEditItemIdentifier]) valid = selectedRows > 0;
+ else if([identifier isEqualToString:RKEditHexItemIdentifier]) valid = selectedRows > 0;
+ else if([identifier isEqualToString:RKExportItemIdentifier]) valid = selectedRows > 0;
+ else if([identifier isEqualToString:RKSaveItemIdentifier]) valid = [self isDocumentEdited];
+ else if([identifier isEqualToString:NSToolbarPrintItemIdentifier]) valid = YES;
+
+ return valid;
+}
+
+#pragma mark -
+#pragma mark Document Management
+
+- (IBAction)showCreateResourceSheet:(id)sender
+{
+ // bug: ResourceDocument allocs a sheet controller, but it's never disposed of
+ CreateResourceSheetController *sheetController = [[CreateResourceSheetController alloc] initWithWindowNibName:@"CreateResourceSheet"];
+ [sheetController showCreateResourceSheet:self];
+}
+
+- (IBAction)showSelectTemplateSheet:(id)sender
+{
+ // bug: ResourceDocument allocs a sheet controller, but it's never disposed of
+// SelectTemplateSheetController *sheetController = [[CreateResourceSheetController alloc] initWithWindowNibName:@"SelectTemplateSheet"];
+// [sheetController showSelectTemplateSheet:self];
+}
+
+- (IBAction)openResources:(id)sender
+{
+ // ignore double-clicks in table header
+ if(sender == outlineView && [outlineView clickedRow] == -1)
+ return;
+
+ Resource *resource;
+ NSArray *selected = [outlineView selectedItems];
+ NSEnumerator *enumerator = [selected objectEnumerator];
+ while(resource = [enumerator nextObject])
+ [self openResourceUsingEditor:resource];
+}
+
+- (IBAction)openResourcesInTemplate:(id)sender
+{
+ // opens the resource in its default template
+ Resource *resource;
+ NSArray *selected = [outlineView selectedItems];
+ NSEnumerator *enumerator = [selected objectEnumerator];
+ while(resource = [enumerator nextObject])
+ [self openResource:resource usingTemplate:[resource type]];
+}
+
+- (IBAction)openResourcesAsHex:(id)sender
+{
+ Resource *resource;
+ NSArray *selected = [outlineView selectedItems];
+ NSEnumerator *enumerator = [selected objectEnumerator];
+ while(resource = [enumerator nextObject])
+ [self openResourceAsHex:resource];
+}
+
+
+/* -----------------------------------------------------------------------------
+ openResourceUsingEditor:
+ Open an editor for the specified Resource instance. This looks up
+ the editor to use in the plugin registry and then instantiates an
+ editor object, handing it the resource. If there is no editor for this
+ type registered, it falls back to the template editor, which in turn
+ uses the hex editor as a fallback.
+
+ REVISIONS:
+ 2003-07-31 UK Changed to use plugin registry instead of file name.
+ -------------------------------------------------------------------------- */
+
+/* Method name should be changed to: -(void)openResource:(Resource *)resource usingEditor:(Class)overrideEditor */
+
+- (void)openResourceUsingEditor:(Resource *)resource
+{
+ Class editorClass = [[RKEditorRegistry defaultRegistry] editorForType:[resource type]];
+
+ // open the resources, passing in the template to use
+ if(editorClass)
+ {
+ // bug: I alloc a plug instance here, but have no idea where I should dealloc it, perhaps the plug ought to call [self autorelease] when it's last window is closed?
+ // update: doug says window controllers automatically release themselves when their window is closed. All default plugs have a window controller as their principal class, but 3rd party ones might not
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceDataDidChange:) name:ResourceDataDidChangeNotification object:resource];
+ id plug = [(id )[editorClass alloc] initWithResource:resource];
+ if(plug) return;
+ }
+
+ // if no editor exists, or the editor is broken, open using template
+ [self openResource:resource usingTemplate:[resource type]];
+}
+
+
+/* -----------------------------------------------------------------------------
+ openResource:usingTemplate:
+ Open a template editor for the specified Resource instance. This looks
+ up the template editor in the plugin registry and then instantiates an
+ editor object, handing it the resource and the template resource to use.
+ If there is no template editor registered, or there is no template for
+ this resource type, it falls back to the hex editor.
+
+ REVISIONS:
+ 2003-07-31 UK Changed to use plugin registry instead of file name.
+ -------------------------------------------------------------------------- */
+
+- (void)openResource:(Resource *)resource usingTemplate:(NSString *)templateName
+{
+ // opens resource in template using TMPL resource with name templateName
+ Class editorClass = [[RKEditorRegistry defaultRegistry] editorForType:@"Template Editor"];
+
+ // TODO: this checks EVERY DOCUMENT for template resources (might not be desired)
+ // TODO: it doesn't, however, check the application's resource map for a matching template!
+ Resource *tmpl = [Resource resourceOfType:@"TMPL" withName:[resource type] inDocument:nil];
+
+ // open the resources, passing in the template to use
+ if(tmpl && editorClass)
+ {
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceDataDidChange:) name:ResourceDataDidChangeNotification object:resource];
+ id plug = [(id )[editorClass alloc] initWithResources:resource, tmpl, nil];
+ if(plug) return;
+ }
+
+ // if no template exists, or template editor is broken, open as hex
+ [self openResourceAsHex:resource];
+}
+
+/*!
+@method openResourceAsHex:
+@author Nicholas Shanks
+@created 2001
+@change 2003-07-31 UK: Changed to use plugin registry instead of file name.
+@description Open a hex editor for the specified Resource instance. This looks up the hexadecimal editor in the plugin registry and then instantiates an editor object, handing it the resource.
+@param resource Resource to edit
+*/
+
+- (void)openResourceAsHex:(Resource *)resource
+{
+ Class editorClass = [[RKEditorRegistry defaultRegistry] editorForType: @"Hexadecimal Editor"];
+ // bug: I alloc a plug instance here, but have no idea where I should dealloc it, perhaps the plug ought to call [self autorelease] when it's last window is closed?
+ // update: doug says window controllers automatically release themselves when their window is closed.
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceDataDidChange:) name:ResourceDataDidChangeNotification object:resource];
+ NSWindowController *plugController = [(id )[editorClass alloc] initWithResource:resource];
+#pragma unused(plugController)
+}
+
+/*!
+@method playSound:
+@abstract Plays the selected carbon 'snd ' resource.
+@author Nicholas Shanks
+@created 2001
+@change 2003-10-22 NS: Moved playing into seperate thread to avoid locking up main thread.
+@pending should really be moved to a 'snd ' editor, but first we'd need to extend the plugin protocol to call the class so it can add such menu items. Of course, we could just make the 'snd ' editor have a button in its window that plays the sound.
+@description This method is called from a menu item which is validated against there being only one selected resource (of type 'snd '), so shouldn't have to deal with playing multiple sounds, though this may of course change in future.
+@param sender ignored
+*/
+
+- (IBAction)playSound:(id)sender
+{
+ // bug: can only cope with one selected item
+ NSData *data = [(Resource *)[outlineView itemAtRow:[outlineView selectedRow]] data];
+ if(data && [data length] != 0)
+ {
+ [NSThread detachNewThreadSelector:@selector(playSoundThreadController:) toTarget:self withObject:data];
+ }
+ else NSBeep();
+}
+
+/*!
+@method playSoundThreadController:
+@abstract Plays a carbon 'snd ' resource.
+@author Nicholas Shanks
+@created 2003-10-22
+@pending should really be moved to a 'snd ' editor, but first we'd need to extend the plugin protocol to call the class so it can add such menu items. Of course, we could just make the 'snd ' editor have a button in its window that plays the sound.
+@description This method was added to prevent having to use AsynchSoundHelper to play them asynchronously in the main thread and all the associated idle checking, which since we have no event loop, would have to have been called from a timer. I'm not sure if the autorelease pool is necessary, as no cocoa objects are created, but an NSData is passed in and messages sent to it, and NSBeep() might need one.
+@param data An NSData object containing the snd resource data to be played.
+*/
+
+- (void)playSoundThreadController:(NSData *)data
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ if(data && [data length] != 0)
+ {
+ // plays sound synchronously, thread exits when sound is done playing
+ SndListPtr sndPtr = (SndListPtr) [data bytes];
+ SndPlay(nil, &sndPtr, false);
+ }
+ else NSBeep();
+ [pool release];
+}
+
+/*!
+@method sound:didFinishPlaying:
+@abstract Called frequently when playing a sound via NSSound. Unused, here for reference and possible future use.
+@author Nicholas Shanks
+@pending should really be moved to a 'snd ' editor, but first we'd need to extend the plugin protocol to call the class so it can add such menu items. Of course, we could just make the 'snd ' editor have a button in its window that plays the sound.
+@param sound The NSSound that is playing.
+@param finished Flag to indicate if it has just finished and that we should clean up.
+*/
+
+- (void)sound:(NSSound *)sound didFinishPlaying:(BOOL)finished
+{
+ // unused because I can't get NSSound to play snd resources, so I use Carbon's SndPlay(), above
+ if(finished) [sound release];
+ NSLog(@"sound released");
+}
+
+- (void)resourceNameWillChange:(NSNotification *)notification
+{
+ // this saves the current resource's name so we can undo the change
+ Resource *resource = (Resource *) [notification object];
+ [[self undoManager] registerUndoWithTarget:resource selector:@selector(setName:) object:[[[resource name] copy] autorelease]];
+ [[self undoManager] setActionName:NSLocalizedString(@"Name Change", nil)];
+}
+
+- (void)resourceIDWillChange:(NSNotification *)notification
+{
+ // this saves the current resource's ID number so we can undo the change
+ Resource *resource = (Resource *) [notification object];
+ [[self undoManager] registerUndoWithTarget:resource selector:@selector(setResID:) object:[[[resource resID] copy] autorelease]];
+ if([[resource name] length] == 0)
+ [[self undoManager] setActionName:NSLocalizedString(@"ID Change", nil)];
+ else [[self undoManager] setActionName:[NSString stringWithFormat:NSLocalizedString(@"ID Change for Ň%@Ó", nil), [resource name]]];
+}
+
+- (void)resourceTypeWillChange:(NSNotification *)notification
+{
+ // this saves the current resource's type so we can undo the change
+ Resource *resource = (Resource *) [notification object];
+ [[self undoManager] registerUndoWithTarget:resource selector:@selector(setType:) object:[[[resource type] copy] autorelease]];
+ if([[resource name] length] == 0)
+ [[self undoManager] setActionName:NSLocalizedString(@"Type Change", nil)];
+ else [[self undoManager] setActionName:[NSString stringWithFormat:NSLocalizedString(@"Type Change for Ň%@Ó", nil), [resource name]]];
+}
+
+- (void)resourceAttributesWillChange:(NSNotification *)notification
+{
+ // this saves the current state of the resource's attributes so we can undo the change
+ Resource *resource = (Resource *) [notification object];
+ [[self undoManager] registerUndoWithTarget:resource selector:@selector(setAttributes:) object:[[[resource attributes] copy] autorelease]];
+ if([[resource name] length] == 0)
+ [[self undoManager] setActionName:NSLocalizedString(@"Attributes Change", nil)];
+ else [[self undoManager] setActionName:[NSString stringWithFormat:NSLocalizedString(@"Attributes Change for Ň%@Ó", nil), [resource name]]];
+}
+
+- (void)resourceDataDidChange:(NSNotification *)notification
+{
+ [self updateChangeCount:NSChangeDone];
+}
+
+#pragma mark -
+#pragma mark Edit Operations
+
+- (IBAction)cut:(id)sender
+{
+ [self copy:sender];
+ [self clear:sender];
+}
+
+- (IBAction)copy:(id)sender
+{
+ #pragma unused(sender)
+ NSArray *selectedItems = [outlineView selectedItems];
+ NSPasteboard *pb = [NSPasteboard pasteboardWithName:NSGeneralPboard];
+ [pb declareTypes:[NSArray arrayWithObject:RKResourcePboardType] owner:self];
+ [pb setData:[NSArchiver archivedDataWithRootObject:selectedItems] forType:RKResourcePboardType];
+}
+
+- (IBAction)paste:(id)sender
+{
+ #pragma unused(sender)
+ NSPasteboard *pb = [NSPasteboard pasteboardWithName:NSGeneralPboard];
+ if([pb availableTypeFromArray:[NSArray arrayWithObject:RKResourcePboardType]])
+ [self pasteResources:[NSUnarchiver unarchiveObjectWithData:[pb dataForType:RKResourcePboardType]]];
+}
+
+- (void)pasteResources:(NSArray *)pastedResources
+{
+ Resource *resource;
+ NSEnumerator *enumerator = [pastedResources objectEnumerator];
+ while(resource = (Resource *) [enumerator nextObject])
+ {
+ // check resource type/ID is available
+ if([dataSource resourceOfType:[resource type] andID:[resource resID]] == nil)
+ {
+ // resource slot is available, paste this one in
+ [dataSource addResource:resource];
+ }
+ else
+ {
+ // resource slot is ocupied, ask user what to do
+ NSMutableArray *remainingResources = [[NSMutableArray alloc] initWithCapacity:1];
+ [remainingResources addObject:resource];
+ [remainingResources addObjectsFromArray:[enumerator allObjects]];
+ NSBeginAlertSheet(@"Paste Error", @"Unique ID", @"Skip", @"Overwrite", mainWindow, self, NULL, @selector(overwritePasteSheetDidDismiss:returnCode:contextInfo:), remainingResources, @"There already exists a resource of type %@ with ID %@. Do you wish to assign the pasted resource a unique ID, overwrite the existing resource, or skip pasting of this resource?", [resource type], [resource resID]);
+ }
+ }
+}
+
+- (void)overwritePasteSheetDidDismiss:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
+{
+ NSMutableArray *remainingResources = [NSMutableArray arrayWithArray:[(NSArray *)contextInfo autorelease]];
+ Resource *resource = [remainingResources objectAtIndex:0];
+ if(returnCode == NSAlertDefaultReturn) // unique ID
+ {
+ Resource *newResource = [Resource resourceOfType:[resource type] andID:[dataSource uniqueIDForType:[resource type]] withName:[resource name] andAttributes:[resource attributes] data:[resource data]];
+ [dataSource addResource:newResource];
+ }
+ else if(NSAlertOtherReturn) // overwrite
+ {
+ [dataSource removeResource:[dataSource resourceOfType:[resource type] andID:[resource resID]]];
+ [dataSource addResource:resource];
+ }
+// else if(NSAlertAlternateReturn) // skip
+
+ // remove top resource and continue paste
+ [remainingResources removeObjectAtIndex:0];
+ [self pasteResources:remainingResources];
+}
+
+- (IBAction)clear:(id)sender
+{
+ #pragma unused(sender)
+ if([prefs boolForKey:@"DeleteResourceWarning"])
+ {
+ NSBeginCriticalAlertSheet(@"Delete Resource", @"Delete", @"Cancel", nil, [self mainWindow], self, @selector(deleteResourcesSheetDidEnd:returnCode:contextInfo:), NULL, nil, @"Please confirm you wish to delete the selected resources.");
+ }
+ else [self deleteSelectedResources];
+}
+
+- (void)deleteResourcesSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
+{
+ #pragma unused(contextInfo)
+ if(returnCode == NSOKButton)
+ [self deleteSelectedResources];
+}
+
+- (void)deleteSelectedResources
+{
+ Resource *resource;
+ NSEnumerator *enumerator;
+ NSArray *selectedItems = [outlineView selectedItems];
+
+ // enumerate through array and delete resources
+ [[self undoManager] beginUndoGrouping];
+ enumerator = [selectedItems reverseObjectEnumerator]; // reverse so an undo will replace items in original order
+ while(resource = [enumerator nextObject])
+ {
+ [dataSource removeResource:resource];
+ if([[resource name] length] == 0)
+ [[self undoManager] setActionName:NSLocalizedString(@"Delete Resource", nil)];
+ else [[self undoManager] setActionName:[NSString stringWithFormat:NSLocalizedString(@"Delete Resource Ň%@Ó", nil), [resource name]]];
+ }
+ [[self undoManager] endUndoGrouping];
+
+ // generalise undo name if more than one was deleted
+ if([outlineView numberOfSelectedRows] > 1)
+ [[self undoManager] setActionName:NSLocalizedString(@"Delete Resources", nil)];
+
+ // deselect resources (otherwise other resources move into selected rows!)
+ [outlineView deselectAll:self];
+}
+
+#pragma mark -
+#pragma mark Accessors
+
+- (NSWindow *)mainWindow
+{
+ return mainWindow;
+}
+
+- (ResourceDataSource *)dataSource
+{
+ return dataSource;
+}
+
+- (NSOutlineView *)outlineView
+{
+ return outlineView;
+}
+
+- (NSArray *)resources
+{
+ return resources;
+}
+
+- (NSData *)creator
+{
+ return creator;
+}
+
+- (NSData *)type
+{
+ return type;
+}
+
+- (IBAction)creatorChanged:(id)sender
+{
+ unsigned long newCreator = 0x00; // creator is nil by default
+ NSData *creatorData = [[sender stringValue] dataUsingEncoding:NSMacOSRomanStringEncoding];
+// NSLog(@"creatorChanged: [sender stringValue] = '%@'; creatorData = '%@'", [sender stringValue], creatorData);
+ if(creatorData && [creatorData length] > 0)
+ {
+ newCreator = ' '; // pad with spaces if not nil
+ [creatorData getBytes:&newCreator length:([creatorData length] < 4? [creatorData length]:4)];
+ }
+ [self setCreator:[NSData dataWithBytes:&newCreator length:4]];
+// NSLog(@"Creator changed to '%@'", [[[NSString alloc] initWithBytes:&newCreator length:4 encoding:NSMacOSRomanStringEncoding] autorelease]);
+}
+
+- (IBAction)typeChanged:(id)sender
+{
+ unsigned long newType = 0x00;
+ NSData *typeData = [[sender stringValue] dataUsingEncoding:NSMacOSRomanStringEncoding];
+// NSLog(@"typeChanged: [sender stringValue] = '%@'; typeData = '%@'", [sender stringValue], typeData);
+ if(typeData && [typeData length] > 0)
+ {
+ newType = ' ';
+ [typeData getBytes:&newType length:([typeData length] < 4? [typeData length]:4)];
+ }
+ [self setType:[NSData dataWithBytes:&newType length:4]];
+// NSLog(@"Type changed to '%@'", [[[NSString alloc] initWithBytes:&newType length:4 encoding:NSMacOSRomanStringEncoding] autorelease]);
+}
+
+- (BOOL)setCreator:(NSData *)newCreator
+{
+ if(![newCreator isEqualToData:creator])
+ {
+ id old = creator;
+ [[NSNotificationCenter defaultCenter] postNotificationName:DocumentInfoWillChangeNotification object:[NSDictionary dictionaryWithObjectsAndKeys:self, @"NSDocument", newCreator, @"creator", nil]];
+ [[self undoManager] registerUndoWithTarget:self selector:@selector(setCreator:) object:creator];
+ [[self undoManager] setActionName:NSLocalizedString(@"Change Creator Code", nil)];
+ creator = [newCreator copy];
+ [old release];
+ [[NSNotificationCenter defaultCenter] postNotificationName:DocumentInfoDidChangeNotification object:[NSDictionary dictionaryWithObjectsAndKeys:self, @"NSDocument", creator, @"creator", nil]];
+ return YES;
+ }
+ else return NO;
+}
+
+- (BOOL)setType:(NSData *)newType
+{
+ if(![newType isEqualToData:type])
+ {
+ id old = type;
+ [[NSNotificationCenter defaultCenter] postNotificationName:DocumentInfoWillChangeNotification object:[NSDictionary dictionaryWithObjectsAndKeys:self, @"NSDocument", newType, @"type", nil]];
+ [[self undoManager] registerUndoWithTarget:self selector:@selector(setType:) object:type];
+ [[self undoManager] setActionName:NSLocalizedString(@"Change File Type", nil)];
+ type = [newType copy];
+ [old release];
+ [[NSNotificationCenter defaultCenter] postNotificationName:DocumentInfoDidChangeNotification object:[NSDictionary dictionaryWithObjectsAndKeys:self, @"NSDocument", type, @"type", nil]];
+ return YES;
+ }
+ else return NO;
+}
+
+- (BOOL)setCreator:(NSData *)newCreator andType:(NSData *)newType
+{
+ BOOL creatorChanged, typeChanged;
+ [[self undoManager] beginUndoGrouping];
+ creatorChanged = [self setCreator:newCreator];
+ typeChanged = [self setType:newType];
+ [[self undoManager] endUndoGrouping];
+ if(creatorChanged && typeChanged)
+ [[self undoManager] setActionName:NSLocalizedString(@"Change Creator & Type", nil)];
+ return (creatorChanged || typeChanged);
+}
+
+@end
diff --git a/Cocoa/Plug-Ins/Hex Editor/HexTextView.m b/Cocoa/Plug-Ins/Hex Editor/HexTextView.m
index 42c5078..7b84a4a 100644
--- a/Cocoa/Plug-Ins/Hex Editor/HexTextView.m
+++ b/Cocoa/Plug-Ins/Hex Editor/HexTextView.m
@@ -486,7 +486,7 @@ static NSRange draggedRange;
@method selectionRangeForProposedRange:granularity:
@abstract Puts insertion pointer between bytes during drag operation
@author Nicholas Shanks
-@updated 2003-11-10 NGS: Changed algorithm.
+@change 2003-11-10 NS: Changed algorithm.
*/
- (unsigned int)_insertionGlyphIndexForDrag:(id )sender
diff --git a/Cocoa/Plug-Ins/Hex Editor/NSData-HexRepresentation.h b/Cocoa/Plug-Ins/Hex Editor/NSData-HexRepresentation.h
new file mode 100644
index 0000000..ec69e5b
--- /dev/null
+++ b/Cocoa/Plug-Ins/Hex Editor/NSData-HexRepresentation.h
@@ -0,0 +1,11 @@
+#import
+
+@interface NSData (ResKnifeHexRepresentationExtensions)
+- (NSString *)hexRepresentation;
+- (NSString *)asciiRepresentation;
+- (NSString *)nonLossyAsciiRepresentation;
+@end
+
+@interface NSString (ResKnifeHexConversionExtensions)
+- (NSData *)dataFromHex;
+@end
\ No newline at end of file
diff --git a/Cocoa/Plug-Ins/Hex Editor/NSData-HexRepresentation.m b/Cocoa/Plug-Ins/Hex Editor/NSData-HexRepresentation.m
new file mode 100644
index 0000000..697c9d2
--- /dev/null
+++ b/Cocoa/Plug-Ins/Hex Editor/NSData-HexRepresentation.m
@@ -0,0 +1,95 @@
+#import "NSData-HexRepresentation.h"
+
+@implementation NSData (ResKnifeHexRepresentationExtensions)
+
+- (NSString *)hexRepresentation
+{
+ int currentByte = 0, dataLength = [self length];
+ char buffer[dataLength*3 -1], hex1, hex2;
+ char *bytes = (char *) [self bytes];
+
+ // return empty string if no data
+ if(dataLength == 0) return [NSString string];
+
+ // calculate bytes
+ for(currentByte = 0; currentByte < dataLength; currentByte++)
+ {
+ hex1 = bytes[currentByte];
+ hex2 = bytes[currentByte];
+ hex1 >>= 4;
+ hex1 &= 0x0F;
+ hex2 &= 0x0F;
+ hex1 += (hex1 < 10)? 0x30 : 0x37;
+ hex2 += (hex2 < 10)? 0x30 : 0x37;
+
+ buffer[currentByte*3] = hex1;
+ buffer[currentByte*3 +1] = hex2;
+ buffer[currentByte*3 +2] = 0x20;
+ }
+
+ return [NSString stringWithCString:buffer length:(dataLength*3 -1)];
+}
+
+- (NSString *)asciiRepresentation
+{
+ int currentByte = 0, dataLength = [self length];
+ char buffer[dataLength];
+ char *bytes = (char *) [self bytes];
+
+ // calculate bytes
+ for(currentByte = 0; currentByte < dataLength; currentByte++)
+ {
+ if(bytes[currentByte] >= 0x20 && bytes[currentByte] < 0x7F)
+ buffer[currentByte] = bytes[currentByte];
+ else buffer[currentByte] = 0x2E; // full stop
+ }
+
+ return [NSString stringWithCString:buffer length:dataLength];
+}
+
+- (NSString *)nonLossyAsciiRepresentation
+{
+ int currentByte = 0, dataLength = [self length];
+ char buffer[dataLength];
+ char *bytes = (char *) [self bytes];
+
+ // calculate bytes
+ for(currentByte = 0; currentByte < dataLength; currentByte++)
+ {
+ if(bytes[currentByte] > 0x20) // doesn't check for < 0x7F
+ buffer[currentByte] = bytes[currentByte];
+// else if(bytes[currentByte] == 0x20)
+// buffer[currentByte] = 0xCA; // nbsp to stop maligned wraps - doesn't work :(
+ else buffer[currentByte] = 0x2E; // full stop
+ }
+
+ return [NSString stringWithCString:buffer length:dataLength];
+}
+
+@end
+
+@implementation NSString (ResKnifeHexConversionExtensions)
+
+- (NSData *)dataFromHex
+{
+ unsigned long actualBytesEncoded = 0;
+ unsigned long maxBytesEncoded = floor([self cStringLength] / 2.0);
+ const char *bytes = [self cString];
+ char *buffer = (char *) malloc(maxBytesEncoded);
+ signed char hex1, hex2;
+ int i;
+
+ for(i = 0; i < maxBytesEncoded * 2;)
+ {
+ hex1 = bytes[i];
+ hex2 = bytes[i+1];
+ hex1 -= (hex1 < 'A')? 0x30 : ((hex1 < 'a')? 0x37 : 0x57); // 0-9 < A-Z < a-z
+ hex2 -= (hex2 < 'A')? 0x30 : ((hex2 < 'a')? 0x37 : 0x57);
+ if(hex1 & 0xF0 || hex2 & 0xF0) { i++; continue; } // invalid character found, move forward one byte and try again
+ buffer[actualBytesEncoded++] = (hex1 << 4) + hex2;
+ i += 2;
+ }
+ return [NSData dataWithBytesNoCopy:buffer length:actualBytesEncoded freeWhenDone:YES];
+}
+
+@end
\ No newline at end of file
diff --git a/Cocoa/Plug-Ins/Notifications.m b/Cocoa/Plug-Ins/Notifications.m
index 97b76e9..68c1cb5 100644
--- a/Cocoa/Plug-Ins/Notifications.m
+++ b/Cocoa/Plug-Ins/Notifications.m
@@ -6,18 +6,16 @@
#import
-NSString *ResourceWillChangeNotification = @"ResourceWillChangeNotification";
-NSString *ResourceNameWillChangeNotification = @"ResourceNameWillChangeNotification";
-NSString *ResourceTypeWillChangeNotification = @"ResourceTypeWillChangeNotification";
-NSString *ResourceIDWillChangeNotification = @"ResourceIDWillChangeNotification";
-NSString *ResourceAttributesWillChangeNotification = @"ResourceAttributesWillChangeNotification";
-NSString *ResourceDataWillChangeNotification = @"ResourceDataWillChangeNotification";
-NSString *ResourceWillBeSavedNotification = @"ResourceWillBeSavedNotification";
+NSString *ResourceWillChangeNotification = @"ResourceWillChange";
+NSString *ResourceNameWillChangeNotification = @"ResourceNameWillChange";
+NSString *ResourceTypeWillChangeNotification = @"ResourceTypeWillChange";
+NSString *ResourceIDWillChangeNotification = @"ResourceIDWillChange";
+NSString *ResourceAttributesWillChangeNotification = @"ResourceAttributesWillChange";
+NSString *ResourceDataWillChangeNotification = @"ResourceDataWillChange";
-NSString *ResourceNameDidChangeNotification = @"ResourceNameDidChangeNotification";
-NSString *ResourceTypeDidChangeNotification = @"ResourceTypeDidChangeNotification";
-NSString *ResourceIDDidChangeNotification = @"ResourceIDDidChangeNotification";
-NSString *ResourceAttributesDidChangeNotification = @"ResourceAttributesDidChangeNotification";
-NSString *ResourceDataDidChangeNotification = @"ResourceDataDidChangeNotification";
-NSString *ResourceDidChangeNotification = @"ResourceDidChangeNotification";
-NSString *ResourceWasSavedNotification = @"ResourceWasSavedNotification";
+NSString *ResourceNameDidChangeNotification = @"ResourceNameDidChange";
+NSString *ResourceTypeDidChangeNotification = @"ResourceTypeDidChange";
+NSString *ResourceIDDidChangeNotification = @"ResourceIDDidChange";
+NSString *ResourceAttributesDidChangeNotification = @"ResourceAttributesDidChange";
+NSString *ResourceDataDidChangeNotification = @"ResourceDataDidChange";
+NSString *ResourceDidChangeNotification = @"ResourceDidChange";
diff --git a/Cocoa/Plug-Ins/ResKnifePluginProtocol.h b/Cocoa/Plug-Ins/ResKnifePluginProtocol.h
index c5a054f..cfebce1 100644
--- a/Cocoa/Plug-Ins/ResKnifePluginProtocol.h
+++ b/Cocoa/Plug-Ins/ResKnifePluginProtocol.h
@@ -1,55 +1,81 @@
#import
#import "ResKnifeResourceProtocol.h"
-/* Your plug-in's principal class must implement initWithResource: else it
-won't be loaded by ResKnife (so neh-neh!), all other methods are optional,
-and thus declared in ResKnifeInformalPluginProtocol. */
+/*!
+@protocol ResKnifePluginProtocol
+@abstract Your plug-in's principal class must implement initWithResource: or initWithResources:, all other methods are optional, and thus declared in ResKnifeInformalPluginProtocol.
+*/
@protocol ResKnifePluginProtocol
-/*! @method initWithResource:
- * @abstract Your plug-in is inited with this call. This allows immediate
- access to the resource you are about to edit, and with this
- information you can set up different windows, etc.
- */
-- (id)initWithResource:(id )newResource;
+/*!
+@method initWithResource:
+@abstract Your plug-in is inited with this call. This allows immediate access to the resource you are about to edit, and with this information you can set up different windows, etc.
+*/
+- (id)initWithResource:(id )inResource;
@end
-/* Optional methods your plugin may implement to provide additional
-functionality: */
-
-@interface ResKnifeInformalPluginProtocol
-
-/*! @method dataForFileExport:
- @abstract Return the data to be saved to disk when your resource is
- exported to a file. By default the host application substitutes
- the raw resource data if you don't implement this. The idea is
- that this export function is non-lossy, i.e. only override this
- if there is a format that is a 100% equivalent to your data. */
-+(NSData*) dataForFileExport: (id )theRes;
-/*! @method extensionForFileExport:
- @abstract If you implement dataForFileExport, return a string here that
- provides the proper file extension for your file. By default the
- host application substitutes the resource type here. */
-+(NSString*) extensionForFileExport: (id )theRes;
-
-/*! @method imageForImageFileExport:
- @abstract Return the image to be saved to disk when your resource is
- exported to an image file. If your resource contains image
- data, this is your opportunity to export it to a well-known
- image format. This will be a lossy conversion to a TIFF
- file. */
-+(NSImage*) imageForImageFileExport: (id )theRes;
-
-@end
-
-
-/* If you're implementing a template editor, you should implement this
- extended protocol instead of the regular plugin protocol: */
-
+/*!
+@protocol ResKnifeTemplatePluginProtocol
+@abstract If you're implementing a template editor, you should implement this extended protocol instead of the regular plugin protocol.
+*/
@protocol ResKnifeTemplatePluginProtocol
-- (id)initWithResources:(id )newResource, ...;
+/*!
+@method initWithResource:
+@abstract Your template editor is inited with this call. The first argument is the resource to edit, the second is the TMPL resource that defines the data structure.
+*/
+- (id)initWithResources:(id )inResource, ...;
-@end
\ No newline at end of file
+@end
+
+
+/*!
+@protocol ResKnifeInformalPluginProtocol
+@abstract Optional methods your plugin may implement to provide additional functionality.
+@author Uli Kusterer
+@change 2005-10-03 NGS: Added UTI, MIME Type and OSType methods, renamed extensionForFileExport: to filenameExtensionForFileExport:
+*/
+@interface ResKnifeInformalPluginProtocol
+
+/*!
+@method dataForFileExport:
+@abstract Return the data to be saved to disk when your resource is exported to a flat file. By default the host application uses the raw resource data if you don't implement this. The idea is that this export function is non-lossy, i.e. only override this if there is a format that is a 100% equivalent to your data.
+*/
++ (NSData *)dataForFileExport:(id )resource;
+
+/* Your plug should implement one of the following four methods.
+ * They are looked for in the order shown below. Only implement one.
+ */
+
+/*!
+@method UTIForFileExport:
+@abstract Regardless of whether you implement dataForFileExport, you should implement this and return the proper Uniform Type Identifier for your file.
+*/
+
++ (NSString *)UTIForFileExport:(id )resource;
+
+/*!
+@method MIMETypeForFileExport:
+@abstract If you do not know the UTI for your file type, but it has a known MIME Type (e.g. image/svg), you can return that here.
+*/
+
++ (NSString *)MIMETypeForFileExport:(id )resource;
+
+/*!
+@method OSTypeForFileExport:
+@abstract If your data has a classical Macintosh OSType code, you can return that here.
+*/
+
++ (NSString *)OSTypeForFileExport:(id )resource;
+
+/*!
+@method filenameExtensionForFileExport:
+@abstract As a last resort, you can return here the filename extension for your resource type.
+ By default the host application substitutes the resource type if you do not implement this.
+*/
+
++ (NSString *)filenameExtensionForFileExport:(id )resource;
+
+@end
diff --git a/Cocoa/Plug-Ins/ResKnifeResourceProtocol.h b/Cocoa/Plug-Ins/ResKnifeResourceProtocol.h
index e12ff09..3e5c98b 100644
--- a/Cocoa/Plug-Ins/ResKnifeResourceProtocol.h
+++ b/Cocoa/Plug-Ins/ResKnifeResourceProtocol.h
@@ -21,39 +21,27 @@
2003-07-31 UK Added document accessor, commented.
========================================================================== */
-/* -----------------------------------------------------------------------------
- Headers:
- -------------------------------------------------------------------------- */
-
#import
-
-/* -----------------------------------------------------------------------------
- Protocol:
- -------------------------------------------------------------------------- */
-
@protocol ResKnifeResourceProtocol
--(void) touch;
--(BOOL) isDirty;
+- (void)touch;
+- (BOOL)isDirty;
--(NSString*) name;
--(void) setName: (NSString*)newName;
--(NSString*) nameForEditorWindow;
+- (NSString *)name;
+- (void)setName:(NSString *)newName;
+- (NSString *)type;
+- (void)setType:(NSString *)newType;
+- (NSNumber *)resID;
+- (void)setResID:(NSNumber *)newResID;
+- (NSNumber *)attributes;
+- (void)setAttributes:(NSNumber *)newAttributes;
+- (NSNumber *)size;
+- (NSData *)data;
+- (void)setData:(NSData *)newData;
--(NSString*) type;
--(void) setType: (NSString*)newType;
--(NSNumber*) resID;
--(void) setResID: (NSNumber*)newResID;
-
--(NSNumber*) attributes;
--(void) setAttributes: (NSNumber*)newAttributes;
-
--(NSNumber*) size;
--(NSData*) data;
--(void) setData: (NSData*)newData;
-
--(NSDocument*) document; // Owner of this resource. Useful for looking for resources in same file as yours.
+- (NSString *)defaultWindowTitle;
+- (NSDocument *)document;
// These methods are used to retrieve resources other than the one you're editing.
// Passing a document of nil will indicate to search in all open documents.
@@ -61,25 +49,19 @@
// All returned objects are auoreleased. Retain if you want to keep them.
// This method may return an empty array
-+ (NSArray *)allResourcesOfType:(NSString *)typeValue inDocument:(NSDocument *)document;
++ (NSArray *)allResourcesOfType:(NSString *)typeValue inDocument:(NSDocument *)searchDocument;
// The next two return the first matching resource found, or nil.
-+ (id)resourceOfType:(NSString *)typeValue andID:(NSNumber *)resIDValue inDocument:(NSDocument *)document;
-+ (id)resourceOfType:(NSString *)typeValue withName:(NSString *)nameValue inDocument:(NSDocument *)document;
++ (id)resourceOfType:(NSString *)typeValue andID:(NSNumber *)resIDValue inDocument:(NSDocument *)searchDocument;
++ (id)resourceOfType:(NSString *)typeValue withName:(NSString *)nameValue inDocument:(NSDocument *)searchDocument;
@end
-/* -----------------------------------------------------------------------------
- Resource Notifications:
- See note in Notifications.m about usage.
- -------------------------------------------------------------------------- */
-
extern NSString *ResourceWillChangeNotification;
extern NSString *ResourceNameWillChangeNotification;
extern NSString *ResourceTypeWillChangeNotification;
extern NSString *ResourceIDWillChangeNotification;
extern NSString *ResourceAttributesWillChangeNotification;
extern NSString *ResourceDataWillChangeNotification;
-extern NSString *ResourceWillBeSavedNotification;
extern NSString *ResourceNameDidChangeNotification;
extern NSString *ResourceTypeDidChangeNotification;
@@ -87,4 +69,3 @@ extern NSString *ResourceIDDidChangeNotification;
extern NSString *ResourceAttributesDidChangeNotification;
extern NSString *ResourceDataDidChangeNotification;
extern NSString *ResourceDidChangeNotification;
-extern NSString *ResourceWasSavedNotification;
\ No newline at end of file
diff --git a/External/MoreFilesX/MoreFilesX.c b/External/MoreFilesX/MoreFilesX.c
index 9e83a74..e614f2b 100644
--- a/External/MoreFilesX/MoreFilesX.c
+++ b/External/MoreFilesX/MoreFilesX.c
@@ -2133,7 +2133,7 @@ BadParameter:
/*****************************************************************************/
-#if 0
+#if COMPILING_ON_JAGUAR_OR_BELOW
/* These methods were added in 10.4, and are not used by ResKnife, so we just comment them out to avoid errors */
OSErr
@@ -2179,7 +2179,6 @@ PBUnlockRangeSync:
return ( result );
}
-
#endif
/*****************************************************************************/
diff --git a/External/MoreFilesX/MoreFilesX.h b/External/MoreFilesX/MoreFilesX.h
index 19a6a5c..8536ed8 100644
--- a/External/MoreFilesX/MoreFilesX.h
+++ b/External/MoreFilesX/MoreFilesX.h
@@ -1 +1 @@
-/*
File: MoreFilesX.h
Contains: A collection of useful high-level File Manager routines
which use the HFS Plus APIs wherever possible.
Version: MoreFilesX 1.0
Copyright: Š 1992-2002 by Apple Computer, Inc., all rights reserved.
You may incorporate this sample code into your applications without
restriction, though the sample code has been provided "AS IS" and the
responsibility for its operation is 100% yours. However, what you are
not permitted to do is to redistribute the source as "DSC Sample Code"
after having made changes. If you're going to re-distribute the source,
we require that you make it clear in the source that the code was
descended from Apple Sample Code, but that you've made changes.
File Ownership:
DRI: Apple Macintosh Developer Technical Support
Other Contact: For bug reports, consult the following page on
the World Wide Web:
http://developer.apple.com/bugreporter/
Technology: DTS Sample Code
Writers:
(JL) Jim Luther
Change History (most recent first):
<1> 1/25/02 JL MoreFilesX 1.0
Notes:
What do those arrows in the documentation for each routine mean?
--> The parameter is an input
<-- The parameter is an output. The pointer to the variable
where the output will be returned (must not be NULL).
<** The parameter is an optional output. If it is not a
NULL pointer, it points to the variable where the output
will be returned. If it is a NULL pointer, the output will
not be returned and will possibly let the routine and the
File Manager do less work. If you don't need an optional output,
don't ask for it.
**> The parameter is an optional input. If it is not a
NULL pointer, it points to the variable containing the
input data. If it is a NULL pointer, the input is not used
and will possibly let the routine and the File Manager
do less work.
*/
#ifndef __MOREFILESX__
#define __MOREFILESX__
#ifndef __MACTYPES__
#include
#endif
#ifndef __FINDER__
#include
#endif
#ifndef __FILES__
#include
#endif
#ifndef __TEXTCOMMON__
#include
#endif
#if PRAGMA_ONCE
#pragma once
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if PRAGMA_IMPORT
#pragma import on
#endif
#if PRAGMA_STRUCT_ALIGN
#pragma options align=mac68k
#elif PRAGMA_STRUCT_PACKPUSH
#pragma pack(push, 2)
#elif PRAGMA_STRUCT_PACK
#pragma pack(2)
#endif
/*****************************************************************************/
#pragma mark ----- FinderInfo and ExtendedFinderInfo -----
/*
* FSGetFinderInfo and FSSetFinderInfo use these unions for Finder information.
*/
union FinderInfo
{
FileInfo file;
FolderInfo folder;
};
typedef union FinderInfo FinderInfo;
union ExtendedFinderInfo
{
ExtendedFileInfo file;
ExtendedFolderInfo folder;
};
typedef union ExtendedFinderInfo ExtendedFinderInfo;
/*****************************************************************************/
#pragma mark ----- GetVolParmsInfoBuffer Macros -----
/*
* Macros to get information out of GetVolParmsInfoBuffer.
*/
/* version 1 field getters */
#define GetVolParmsInfoVersion(volParms) \
((volParms)->vMVersion)
#define GetVolParmsInfoAttrib(volParms) \
((volParms)->vMAttrib)
#define GetVolParmsInfoLocalHand(volParms) \
((volParms)->vMLocalHand)
#define GetVolParmsInfoServerAdr(volParms) \
((volParms)->vMServerAdr)
/* version 2 field getters (assume zero result if version < 2) */
#define GetVolParmsInfoVolumeGrade(volParms) \
(((volParms)->vMVersion >= 2) ? (volParms)->vMVolumeGrade : 0)
#define GetVolParmsInfoForeignPrivID(volParms) \
(((volParms)->vMVersion >= 2) ? (volParms)->vMForeignPrivID : 0)
/* version 3 field getters (assume zero result if version < 3) */
#define GetVolParmsInfoExtendedAttributes(volParms) \
(((volParms)->vMVersion >= 3) ? (volParms)->vMExtendedAttributes : 0)
/* attribute bits supported by all versions of GetVolParmsInfoBuffer */
#define VolIsNetworkVolume(volParms) \
((volParms)->vMServerAdr != 0)
#define VolHasLimitFCBs(volParms) \
(((volParms)->vMAttrib & (1L << bLimitFCBs)) != 0)
#define VolHasLocalWList(volParms) \
(((volParms)->vMAttrib & (1L << bLocalWList)) != 0)
#define VolHasNoMiniFndr(volParms) \
(((volParms)->vMAttrib & (1L << bNoMiniFndr)) != 0)
#define VolHasNoVNEdit(volParms) \
(((volParms)->vMAttrib & (1L << bNoVNEdit)) != 0)
#define VolHasNoLclSync(volParms) \
(((volParms)->vMAttrib & (1L << bNoLclSync)) != 0)
#define VolHasTrshOffLine(volParms) \
(((volParms)->vMAttrib & (1L << bTrshOffLine)) != 0)
#define VolHasNoSwitchTo(volParms) \
(((volParms)->vMAttrib & (1L << bNoSwitchTo)) != 0)
#define VolHasNoDeskItems(volParms) \
(((volParms)->vMAttrib & (1L << bNoDeskItems)) != 0)
#define VolHasNoBootBlks(volParms) \
(((volParms)->vMAttrib & (1L << bNoBootBlks)) != 0)
#define VolHasAccessCntl(volParms) \
(((volParms)->vMAttrib & (1L << bAccessCntl)) != 0)
#define VolHasNoSysDir(volParms) \
(((volParms)->vMAttrib & (1L << bNoSysDir)) != 0)
#define VolHasExtFSVol(volParms) \
(((volParms)->vMAttrib & (1L << bHasExtFSVol)) != 0)
#define VolHasOpenDeny(volParms) \
(((volParms)->vMAttrib & (1L << bHasOpenDeny)) != 0)
#define VolHasCopyFile(volParms) \
(((volParms)->vMAttrib & (1L << bHasCopyFile)) != 0)
#define VolHasMoveRename(volParms) \
(((volParms)->vMAttrib & (1L << bHasMoveRename)) != 0)
#define VolHasDesktopMgr(volParms) \
(((volParms)->vMAttrib & (1L << bHasDesktopMgr)) != 0)
#define VolHasShortName(volParms) \
(((volParms)->vMAttrib & (1L << bHasShortName)) != 0)
#define VolHasFolderLock(volParms) \
(((volParms)->vMAttrib & (1L << bHasFolderLock)) != 0)
#define VolHasPersonalAccessPrivileges(volParms) \
(((volParms)->vMAttrib & (1L << bHasPersonalAccessPrivileges)) != 0)
#define VolHasUserGroupList(volParms) \
(((volParms)->vMAttrib & (1L << bHasUserGroupList)) != 0)
#define VolHasCatSearch(volParms) \
(((volParms)->vMAttrib & (1L << bHasCatSearch)) != 0)
#define VolHasFileIDs(volParms) \
(((volParms)->vMAttrib & (1L << bHasFileIDs)) != 0)
#define VolHasBTreeMgr(volParms) \
(((volParms)->vMAttrib & (1L << bHasBTreeMgr)) != 0)
#define VolHasBlankAccessPrivileges(volParms) \
(((volParms)->vMAttrib & (1L << bHasBlankAccessPrivileges)) != 0)
#define VolSupportsAsyncRequests(volParms) \
(((volParms)->vMAttrib & (1L << bSupportsAsyncRequests)) != 0)
#define VolSupportsTrashVolumeCache(volParms) \
(((volParms)->vMAttrib & (1L << bSupportsTrashVolumeCache)) != 0)
/* attribute bits supported by version 3 and greater versions of GetVolParmsInfoBuffer */
#define VolIsEjectable(volParms) \
((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bIsEjectable)) != 0)
#define VolSupportsHFSPlusAPIs(volParms) \
((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsHFSPlusAPIs)) != 0)
#define VolSupportsFSCatalogSearch(volParms) \
((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsFSCatalogSearch)) != 0)
#define VolSupportsFSExchangeObjects(volParms) \
((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsFSExchangeObjects)) != 0)
#define VolSupports2TBFiles(volParms) \
((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupports2TBFiles)) != 0)
#define VolSupportsLongNames(volParms) \
((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsLongNames)) != 0)
#define VolSupportsMultiScriptNames(volParms) \
((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsMultiScriptNames)) != 0)
#define VolSupportsNamedForks(volParms) \
((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsNamedForks)) != 0)
#define VolSupportsSubtreeIterators(volParms) \
((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsSubtreeIterators)) != 0)
#define VolL2PCanMapFileBlocks(volParms) \
((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bL2PCanMapFileBlocks)) != 0)
#define VolParentModDateChanges(volParms) \
((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bParentModDateChanges)) != 0)
#define VolAncestorModDateChanges(volParms) \
((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bAncestorModDateChanges)) != 0)
#define VolSupportsSymbolicLinks(volParms) \
((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsSymbolicLinks)) != 0)
#define VolIsAutoMounted(volParms) \
((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bIsAutoMounted)) != 0)
/*****************************************************************************/
#pragma mark ----- userPrivileges Bit Masks and Macros -----
/*
* Bit masks and macros to get common information out of userPrivileges byte
* returned by FSGetCatalogInfo.
*
* Note: The userPrivileges byte is the same as the ioACUser byte returned
* by PBGetCatInfo, and is the 1's complement of the user's privileges
* byte returned in ioACAccess by PBHGetDirAccess. That's where the
* ioACUser names came from.
*
* The userPrivileges are user's effective privileges based on the
* user ID and the groups that user belongs to, and the owner, group,
* and everyone privileges for the given directory.
*/
enum
{
/* mask for just the access restriction bits */
kioACUserAccessMask = (kioACUserNoSeeFolderMask +
kioACUserNoSeeFilesMask +
kioACUserNoMakeChangesMask),
/* common access privilege settings */
kioACUserFull = 0x00, /* no access restiction bits on */
kioACUserNone = kioACUserAccessMask, /* all access restiction bits on */
kioACUserDropBox = (kioACUserNoSeeFolderMask +
kioACUserNoSeeFilesMask), /* make changes, but not see files or folders */
kioACUserBulletinBoard = kioACUserNoMakeChangesMask /* see files and folders, but not make changes */
};
/* Macros for testing ioACUser bits. */
#define UserIsOwner(userPrivileges) \
(((userPrivileges) & kioACUserNotOwnerMask) == 0)
#define UserHasFullAccess(userPrivileges) \
(((userPrivileges) & (kioACUserAccessMask)) == kioACUserFull)
#define UserHasDropBoxAccess(userPrivileges) \
(((userPrivileges) & kioACUserAccessMask) == kioACUserDropBox)
#define UserHasBulletinBoard(userPrivileges) \
(((userPrivileges) & kioACUserAccessMask) == kioACUserBulletinBoard)
#define UserHasNoAccess(userPrivileges) \
(((userPrivileges) & kioACUserAccessMask) == kioACUserNone)
/*****************************************************************************/
#pragma mark ----- File Access Routines -----
/*****************************************************************************/
#pragma mark FSCopyFork
OSErr
FSCopyFork(
SInt16 srcRefNum,
SInt16 dstRefNum,
void *copyBufferPtr,
ByteCount copyBufferSize);
/*
The FSCopyFork function copies all data from the source fork to the
destination fork of open file forks and makes sure the destination EOF
is equal to the source EOF.
srcRefNum --> The source file reference number.
dstRefNum --> The destination file reference number.
copyBufferPtr --> Pointer to buffer to use during copy. The
buffer should be at least 4K-bytes minimum.
The larger the buffer, the faster the copy
(up to a point).
copyBufferSize --> The size of the copy buffer.
*/
/*****************************************************************************/
#pragma mark ----- Volume Access Routines -----
/*****************************************************************************/
#pragma mark FSGetVolParms
OSErr
FSGetVolParms(
FSVolumeRefNum volRefNum,
UInt32 bufferSize,
GetVolParmsInfoBuffer *volParmsInfo,
UInt32 *actualInfoSize);
/*
The FSGetVolParms function returns information about the characteristics
of a volume. A result of paramErr usually just means the volume doesn't
support GetVolParms and the feature you were going to check
for isn't available.
volRefNum --> Volume specification.
bufferSize --> Size of buffer pointed to by volParmsInfo.
volParmsInfo <-- A GetVolParmsInfoBuffer record where the volume
attributes information is returned.
actualInfoSize <-- The number of bytes actually returned
in volParmsInfo.
__________
Also see: The GetVolParmsInfoBuffer Macros for checking attribute bits
in this file
*/
/*****************************************************************************/
#pragma mark FSGetVRefNum
OSErr
FSGetVRefNum(
const FSRef *ref,
FSVolumeRefNum *vRefNum);
/*
The FSGetVRefNum function determines the volume reference
number of a volume from a FSRef.
ref --> The FSRef.
vRefNum <-- The volume reference number.
*/
/*****************************************************************************/
#pragma mark FSGetVInfo
OSErr
FSGetVInfo(
FSVolumeRefNum volume,
HFSUniStr255 *volumeName, /* can be NULL */
UInt64 *freeBytes, /* can be NULL */
UInt64 *totalBytes); /* can be NULL */
/*
The FSGetVInfo function returns the name, available space (in bytes),
and total space (in bytes) for the specified volume.
volume --> The volume reference number.
volumeName <** An optional pointer to a HFSUniStr255.
If not NULL, the volume name will be returned in
the HFSUniStr255.
freeBytes <** An optional pointer to a UInt64.
If not NULL, the number of free bytes on the
volume will be returned in the UInt64.
totalBytes <** An optional pointer to a UInt64.
If not NULL, the total number of bytes on the
volume will be returned in the UInt64.
*/
/*****************************************************************************/
#pragma mark FSGetVolFileSystemID
OSErr
FSGetVolFileSystemID(
FSVolumeRefNum volume,
UInt16 *fileSystemID, /* can be NULL */
UInt16 *signature); /* can be NULL */
/*
The FSGetVolFileSystemID function returns the file system ID and signature
of a mounted volume. The file system ID identifies the file system
that handles requests to a particular volume. The signature identifies the
volume type of the volume (for example, FSID 0 is Macintosh HFS Plus, HFS
or MFS, where a signature of 0x4244 identifies the volume as HFS).
Here's a partial list of file system ID numbers (only Apple's file systems
are listed):
FSID File System
----- -----------------------------------------------------
$0000 Macintosh HFS Plus, HFS or MFS
$0100 ProDOS File System
$0101 PowerTalk Mail Enclosures
$4147 ISO 9660 File Access (through Foreign File Access)
$4242 High Sierra File Access (through Foreign File Access)
$464D QuickTake File System (through Foreign File Access)
$4953 Macintosh PC Exchange (MS-DOS)
$4A48 Audio CD Access (through Foreign File Access)
$4D4B Apple Photo Access (through Foreign File Access)
$6173 AppleShare (later versions of AppleShare only)
See the Technical Note "FL 35 - Determining Which File System
Is Active" and the "Guide to the File System Manager" for more
information.
volume --> The volume reference number.
fileSystemID <** An optional pointer to a UInt16.
If not NULL, the volume's file system ID will
be returned in the UInt16.
signature <** An optional pointer to a UInt16.
If not NULL, the volume's signature will
be returned in the UInt16.
*/
/*****************************************************************************/
#pragma mark FSGetMountedVolumes
OSErr
FSGetMountedVolumes(
FSRef ***volumeRefsHandle, /* pointer to handle of FSRefs */
ItemCount *numVolumes);
/*
The FSGetMountedVolumes function returns the list of volumes currently
mounted in an array of FSRef records. The array of FSRef records is
returned in a Handle, volumeRefsHandle, which is allocated by
FSGetMountedVolumes. The caller is responsible for disposing of
volumeRefsHandle if the FSGetMountedVolumes returns noErr.
volumeRefsHandle <-- Pointer to an FSRef Handle where the array of
FSRefs is to be returned.
numVolumes <-- The number of volumes returned in the array.
*/
/*****************************************************************************/
#pragma mark ----- FSRef/FSpec/Path/Name Conversion Routines -----
/*****************************************************************************/
#pragma mark FSRefMakeFSSpec
OSErr
FSRefMakeFSSpec(
const FSRef *ref,
FSSpec *spec);
/*
The FSRefMakeFSSpec function returns an FSSpec for the file or
directory specified by the ref parameter.
ref --> An FSRef specifying the file or directory.
spec <-- The FSSpec.
*/
/*****************************************************************************/
#pragma mark FSMakeFSRef
OSErr
FSMakeFSRef(
FSVolumeRefNum volRefNum,
SInt32 dirID,
ConstStr255Param name,
FSRef *ref);
/*
The FSMakeFSRef function creates an FSRef from the traditional
volume reference number, directory ID and pathname inputs. It is
functionally equivalent to FSMakeFSSpec followed by FSpMakeFSRef.
volRefNum --> Volume specification.
dirID --> Directory specification.
name --> The file or directory name, or NULL.
ref <-- The FSRef.
*/
/*****************************************************************************/
#pragma mark FSMakePath
OSStatus
FSMakePath(
SInt16 vRefNum,
SInt32 dirID,
ConstStr255Param name,
UInt8 *path,
UInt32 maxPathSize);
/*
The FSMakePath function creates a pathname from the traditional volume reference
number, directory ID, and pathname inputs. It is functionally equivalent to
FSMakeFSSpec, FSpMakeFSRef, FSRefMakePath.
volRefNum --> Volume specification.
dirID --> Directory specification.
name --> The file or directory name, or NULL.
path <-- A pointer to a buffer which FSMakePath will
fill with a C string representing the pathname
to the file or directory specified. The format of
the pathname returned can be determined with the
Gestalt selector gestaltFSAttr's
gestaltFSUsesPOSIXPathsForConversion bit.
If the gestaltFSUsesPOSIXPathsForConversion bit is
clear, the pathname is a Mac OS File Manager full
pathname in a C string, and file or directory names
in the pathname may be mangled as returned by
the File Manager. If the
gestaltFSUsesPOSIXPathsForConversion bit is set,
the pathname is a UTF8 encoded POSIX absolute
pathname in a C string. In either case, the
pathname returned can be passed back to
FSPathMakeRef to create an FSRef to the file or
directory, or FSPathMakeFSSpec to craete an FSSpec
to the file or directory.
maxPathSize --> The size of the path buffer in bytes. If the path
buffer is too small for the pathname string,
FSMakePath returns pathTooLongErr or
buffersTooSmall.
*/
/*****************************************************************************/
#pragma mark FSPathMakeFSSpec
OSStatus
FSPathMakeFSSpec(
const UInt8 *path,
FSSpec *spec,
Boolean *isDirectory); /* can be NULL */
/*
The FSPathMakeFSSpec function converts a pathname to an FSSpec.
path --> A pointer to a C String that is the pathname. The
format of the pathname you must supply can be
determined with the Gestalt selector gestaltFSAttr's
gestaltFSUsesPOSIXPathsForConversion bit.
If the gestaltFSUsesPOSIXPathsForConversion bit is
clear, the pathname must be a Mac OS File Manager
full pathname in a C string. If the
gestaltFSUsesPOSIXPathsForConversion bit is set,
the pathname must be a UTF8 encoded POSIX absolute
pathname in a C string.
spec <-- The FSSpec.
isDirectory <** An optional pointer to a Boolean.
If not NULL, true will be returned in the Boolean
if the specified path is a directory, or false will
be returned in the Boolean if the specified path is
a file.
*/
/*****************************************************************************/
#pragma mark UnicodeNameGetHFSName
OSErr
UnicodeNameGetHFSName(
UniCharCount nameLength,
const UniChar *name,
TextEncoding textEncodingHint,
Boolean isVolumeName,
Str31 hfsName);
/*
The UnicodeNameGetHFSName function converts a Unicode string
to a Pascal Str31 (or Str27) string using an algorithm similar to that used
by the File Manager. Note that if the name is too long or cannot be converted
using the given text encoding hint, you will get an error instead of the
mangled name that the File Manager would return.
nameLength --> Number of UniChar in name parameter.
name --> The Unicode string to convert.
textEncodingHint --> The text encoding hint used for the conversion.
You can pass kTextEncodingUnknown to use the
"default" textEncodingHint.
isVolumeName --> If true, the output name will be limited to
27 characters (kHFSMaxVolumeNameChars). If false,
the output name will be limited to 31 characters
(kHFSMaxFileNameChars).
hfsName <-- The hfsName as a Pascal string.
__________
Also see: HFSNameGetUnicodeName
*/
/*****************************************************************************/
#pragma mark HFSNameGetUnicodeName
OSErr
HFSNameGetUnicodeName(
ConstStr31Param hfsName,
TextEncoding textEncodingHint,
HFSUniStr255 *unicodeName);
/*
The HFSNameGetUnicodeName function converts a Pascal Str31 string to an
Unicode HFSUniStr255 string using the same routines as the File Manager.
hfsName --> The Pascal string to convert.
textEncodingHint --> The text encoding hint used for the conversion.
You can pass kTextEncodingUnknown to use the
"default" textEncodingHint.
unicodeName <-- The Unicode string.
__________
Also see: UnicodeNameGetHFSName
*/
/*****************************************************************************/
#pragma mark ----- File/Directory Manipulation Routines -----
/*****************************************************************************/
#pragma mark FSRefValid
Boolean FSRefValid(const FSRef *ref);
/*
The FSRefValid function determines if an FSRef is valid. If the result is
true, then the FSRef refers to an existing file or directory.
ref --> FSRef to a file or directory.
*/
/*****************************************************************************/
#pragma mark FSGetParentRef
OSErr
FSGetParentRef(
const FSRef *ref,
FSRef *parentRef);
/*
The FSGetParentRef function gets the parent directory FSRef of the
specified object.
Note: FSRefs always point to real file system objects. So, there cannot
be a FSRef to the parent of volume root directories. If you call
FSGetParentRef with a ref to the root directory of a volume, the
function result will be noErr and the parentRef will be invalid (using it
for other file system requests will fail).
ref --> FSRef to a file or directory.
parentRef <-- The parent directory's FSRef.
*/
/*****************************************************************************/
#pragma mark FSGetFileDirName
OSErr
FSGetFileDirName(
const FSRef *ref,
HFSUniStr255 *outName);
/*
The FSGetFileDirName function gets the name of the file or directory
specified.
ref --> FSRef to a file or directory.
outName <-- The file or directory name.
*/
/*****************************************************************************/
#pragma mark FSGetNodeID
OSErr
FSGetNodeID(
const FSRef *ref,
long *nodeID, /* can be NULL */
Boolean *isDirectory); /* can be NULL */
/*
The GetNodeIDFromFSRef function gets the node ID number of the
file or directory specified (note: the node ID is the directory ID
for directories).
ref --> FSRef to a file or directory.
nodeID <** An optional pointer to a long.
If not NULL, the node ID will be returned in
the long.
isDirectory <** An optional pointer to a Boolean.
If not NULL, true will be returned in the Boolean
if the object is a directory, or false will be
returned in the Boolean if object is a file.
*/
/*****************************************************************************/
#pragma mark FSGetUserPrivilegesPermissions
OSErr
FSGetUserPrivilegesPermissions(
const FSRef *ref,
UInt8 *userPrivileges, /* can be NULL */
UInt32 permissions[4]); /* can be NULL */
/*
The FSGetUserPrivilegesPermissions function gets the userPrivileges and/or
permissions of the file or directory specified.
ref --> FSRef to a file or directory.
userPrivileges <** An optional pointer to a UInt8.
If not NULL, the userPrivileges will be returned
in the UInt8.
permissions <** An optional pointer to an UInt32[4] array.
If not NULL, the permissions will be returned
in the UInt32[4] array.
*/
/*****************************************************************************/
#pragma mark FSCheckLock
OSErr
FSCheckLock(
const FSRef *ref);
/*
The FSCheckLock function determines if a file or directory is locked.
If FSCheckLock returns noErr, then the file or directory is not locked
and the volume it is on is not locked either. If FSCheckLock returns
fLckdErr, then the file or directory is locked. If FSCheckLock returns
wPrErr, then the volume is locked by hardware (i.e., locked tab on
removable media). If FSCheckLock returns vLckdErr, then the volume is
locked by software.
ref --> FSRef to a file or directory.
*/
/*****************************************************************************/
#pragma mark FSGetForkSizes
OSErr
FSGetForkSizes(
const FSRef *ref,
UInt64 *dataLogicalSize, /* can be NULL */
UInt64 *rsrcLogicalSize); /* can be NULL */
/*
The FSGetForkSizes returns the size of the data and/or resource fork for
the specified file.
ref --> FSRef to a file or directory.
dataLogicalSize <** An optional pointer to a UInt64.
If not NULL, the data fork's size will be
returned in the UInt64.
rsrcLogicalSize <** An optional pointer to a UInt64.
If not NULL, the resource fork's size will be
returned in the UInt64.
__________
Also see: FSGetTotalForkSizes
*/
/*****************************************************************************/
#pragma mark FSGetTotalForkSizes
OSErr
FSGetTotalForkSizes(
const FSRef *ref,
UInt64 *totalLogicalSize, /* can be NULL */
UInt64 *totalPhysicalSize, /* can be NULL */
ItemCount *forkCount); /* can be NULL */
/*
The FSGetTotalForkSizes returns the total logical size and/or the total
physical size of the specified file (i.e., it adds the sizes of all file
forks). It optionally returns the number of file forks.
ref --> FSRef to a file or directory.
totalLogicalSize <** An optional pointer to a UInt64.
If not NULL, the sum of all fork logical sizes
will be returned in the UInt64.
totalPhysicalSize <** An optional pointer to a UInt64.
If not NULL, the sum of all fork physical sizes
will be returned in the UInt64.
forkCount <** An optional pointer to a ItemCount.
If not NULL, the number of file forks
will be returned in the ItemCount.
__________
Also see: FSGetForkSizes
*/
/*****************************************************************************/
#pragma mark FSBumpDate
OSErr
FSBumpDate(
const FSRef *ref);
/*
The FSBumpDate function changes the content modification date of a file
or directory to the current date/time. If the content modification date
is already equal to the current date/time, then add one second to the
content modification date.
ref --> FSRef to a file or directory.
*/
/*****************************************************************************/
#pragma mark FSGetFinderInfo
OSErr
FSGetFinderInfo(
const FSRef *ref,
FinderInfo *info, /* can be NULL */
ExtendedFinderInfo *extendedInfo, /* can be NULL */
Boolean *isDirectory); /* can be NULL */
/*
The FSGetFinderInfo function gets the finder information for a file or
directory.
ref --> FSRef to a file or directory.
info <** An optional pointer to a FinderInfo.
If not NULL, the FileInfo (if ref is a file) or
the FolderInfo (if ref is a folder) will be
returned in the FinderInfo.
extendedInfo <** An optional pointer to a ExtendedFinderInfo.
If not NULL, the ExtendedFileInfo (if ref is a file)
or the ExtendedFolderInfo (if ref is a folder) will
be returned in the ExtendedFinderInfo.
isDirectory <** An optional pointer to a Boolean.
If not NULL, true will be returned in the Boolean
if the object is a directory, or false will be
returned in the Boolean if object is a file.
__________
Also see: FSSetFinderInfo
*/
/*****************************************************************************/
#pragma mark FSSetFinderInfo
OSErr
FSSetFinderInfo(
const FSRef *ref,
const FinderInfo *info, /* can be NULL */
const ExtendedFinderInfo *extendedInfo); /* can be NULL */
/*
The FSSetFinderInfo function sets the finder information for a file or
directory.
ref --> FSRef to a file or directory.
info **> A pointer to a FinderInfo record with the new
FileInfo (if ref is a file) or new FolderInfo
(if ref is a folder), or NULL if the FinderInfo
is not to be changed.
extendedInfo **> A pointer to a FinderInfo record with the new
ExtendedFileInfo (if ref is a file) or new
ExtendedFolderInfo (if ref is a folder), or NULL
if the ExtendedFinderInfo is not to be changed.
__________
Also see: FSGetFinderInfo
*/
/*****************************************************************************/
#pragma mark FSChangeCreatorType
OSErr
FSChangeCreatorType(
const FSRef *ref,
OSType fileCreator,
OSType fileType);
/*
The FSChangeCreatorType function changes the creator and/or file type of a file.
ref --> FSRef to a file.
creator --> The new creator type or 0x00000000 to leave
the creator type alone.
fileType --> The new file type or 0x00000000 to leave the
file type alone.
*/
/*****************************************************************************/
#pragma mark FSChangeFinderFlags
OSErr
FSChangeFinderFlags(
const FSRef *ref,
Boolean setBits,
UInt16 flagBits);
/*
The FSChangeFinderFlags function sets or clears flag bits in
the finderFlags field of a file's FileInfo record or a
directory's FolderInfo record.
ref --> FSRef to a file or directory.
setBits --> If true, then set the bits specified in flagBits.
If false, then clear the bits specified in flagBits.
flagBits --> The flagBits parameter specifies which Finder Flag
bits to set or clear. If a bit in flagBits is set,
then the same bit in fdFlags is either set or
cleared depending on the state of the setBits
parameter.
*/
/*****************************************************************************/
#pragma mark FSSetInvisible
OSErr
FSSetInvisible(
const FSRef *ref);
#pragma mark FSClearInvisible
OSErr
FSClearInvisible(
const FSRef *ref);
/*
The FSSetInvisible and FSClearInvisible functions set or clear the
kIsInvisible bit in the finderFlags field of the specified file or
directory's finder information.
ref --> FSRef to a file or directory.
*/
/*****************************************************************************/
#pragma mark FSSetNameLocked
OSErr
FSSetNameLocked(
const FSRef *ref);
#pragma mark FSClearNameLocked
OSErr
FSClearNameLocked(
const FSRef *ref);
/*
The FSSetNameLocked and FSClearNameLocked functions set or clear the
kNameLocked bit bit in the finderFlags field of the specified file or
directory's finder information.
ref --> FSRef to a file or directory.
*/
/*****************************************************************************/
#pragma mark FSSetIsStationery
OSErr
FSSetIsStationery(
const FSRef *ref);
#pragma mark FSClearIsStationery
OSErr
FSClearIsStationery(
const FSRef *ref);
/*
The FSSetIsStationery and FSClearIsStationery functions set or clear the
kIsStationery bit bit in the finderFlags field of the specified file or
directory's finder information.
ref --> FSRef to a file or directory.
*/
/*****************************************************************************/
#pragma mark FSSetHasCustomIcon
OSErr
FSSetHasCustomIcon(
const FSRef *ref);
#pragma mark FSClearHasCustomIcon
OSErr
FSClearHasCustomIcon(
const FSRef *ref);
/*
The FSSetHasCustomIcon and FSClearHasCustomIcon functions set or clear the
kHasCustomIcon bit bit in the finderFlags field of the specified file or
directory's finder information.
ref --> FSRef to a file or directory.
*/
/*****************************************************************************/
#pragma mark FSClearHasBeenInited
OSErr
FSClearHasBeenInited(
const FSRef *ref);
/*
The FSClearHasBeenInited function clears the kHasBeenInited bit in the
finderFlags field of the specified file or directory's finder information.
Note: There is no FSSetHasBeenInited function because ONLY the Finder
should set the kHasBeenInited bit.
ref --> FSRef to a file or directory.
*/
/*****************************************************************************/
#pragma mark FSCopyFileMgrAttributes
OSErr
FSCopyFileMgrAttributes(
const FSRef *sourceRef,
const FSRef *destinationRef,
Boolean copyLockBit);
/*
The CopyFileMgrAttributes function copies all File Manager attributes
from the source file or directory to the destination file or directory.
If copyLockBit is true, then set the locked state of the destination
to match the source.
sourceRef --> FSRef to a file or directory.
destinationRef --> FSRef to a file or directory.
copyLockBit --> If true, set the locked state of the destination
to match the source.
*/
/*****************************************************************************/
#pragma mark FSMoveRenameObjectUnicode
OSErr
FSMoveRenameObjectUnicode(
const FSRef *ref,
const FSRef *destDirectory,
UniCharCount nameLength,
const UniChar *name, /* can be NULL (no rename during move) */
TextEncoding textEncodingHint,
FSRef *newRef); /* if function fails along the way, newRef is final location of file */
/*
The FSMoveRenameObjectUnicode function moves a file or directory and
optionally renames it. The source and destination locations must be on
the same volume.
Note: If the input ref parameter is invalid, this call will fail and
newRef, like ref, will be invalid.
ref --> FSRef to a file or directory.
destDirectory --> FSRef to the destination directory.
nameLength --> Number of UniChar in name parameter.
name --> An Unicode string with the new name for the
moved object, or NULL if no rename is wanted.
textEncodingHint --> The text encoding hint used for the rename.
You can pass kTextEncodingUnknown to use the
"default" textEncodingHint.
newRef <-- The new FSRef of the object moved. Note that if
this function fails at any step along the way,
newRef is still then final location of the object.
*/
/*****************************************************************************/
#pragma mark FSDeleteContainerContents
OSErr
FSDeleteContainerContents(
const FSRef *container);
/*
The FSDeleteContainerContents function deletes the contents of a container
directory. All files and subdirectories in the specified container are
deleted. If a locked file or directory is encountered, it is unlocked and
then deleted. If any unexpected errors are encountered,
FSDeleteContainerContents quits and returns to the caller.
container --> FSRef to a directory.
__________
Also see: FSDeleteContainer
*/
/*****************************************************************************/
#pragma mark FSDeleteContainer
OSErr
FSDeleteContainer(
const FSRef *container);
/*
The FSDeleteContainer function deletes a container directory and its contents.
All files and subdirectories in the specified container are deleted.
If a locked file or directory is encountered, it is unlocked and then
deleted. After deleting the container's contents, the container is
deleted. If any unexpected errors are encountered, FSDeleteContainer
quits and returns to the caller.
container --> FSRef to a directory.
__________
Also see: FSDeleteContainerContents
*/
/*****************************************************************************/
#pragma mark IterateContainerFilterProcPtr
typedef CALLBACK_API( Boolean , IterateContainerFilterProcPtr ) (
Boolean containerChanged,
ItemCount currentLevel,
const FSCatalogInfo *catalogInfo,
const FSRef *ref,
const FSSpec *spec,
const HFSUniStr255 *name,
void *yourDataPtr);
/*
This is the prototype for the IterateContainerFilterProc function which
is called once for each file and directory found by FSIterateContainer.
The IterateContainerFilterProc can use the read-only data it receives for
whatever it wants.
The result of the IterateContainerFilterProc function indicates if
iteration should be stopped. To stop iteration, return true; to continue
iteration, return false.
The yourDataPtr parameter can point to whatever data structure you might
want to access from within the IterateContainerFilterProc.
containerChanged --> Set to true if the container's contents changed
during iteration.
currentLevel --> The current recursion level into the container.
1 = the container, 2 = the container's immediate
subdirectories, etc.
catalogInfo --> The catalog information for the current object.
Only the fields requested by the whichInfo
parameter passed to FSIterateContainer are valid.
ref --> The FSRef to the current object.
spec --> The FSSpec to the current object if the wantFSSpec
parameter passed to FSIterateContainer is true.
name --> The name of the current object if the wantName
parameter passed to FSIterateContainer is true.
yourDataPtr --> An optional pointer to whatever data structure you
might want to access from within the
IterateFilterProc.
result <-- To stop iteration, return true; to continue
iteration, return false.
__________
Also see: FSIterateContainer
*/
/*****************************************************************************/
#pragma mark CallIterateContainerFilterProc
#define CallIterateContainerFilterProc(userRoutine, containerChanged, currentLevel, catalogInfo, ref, spec, name, yourDataPtr) \
(*(userRoutine))((containerChanged), (currentLevel), (catalogInfo), (ref), (spec), (name), (yourDataPtr))
/*****************************************************************************/
#pragma mark FSIterateContainer
OSErr
FSIterateContainer(
const FSRef *container,
ItemCount maxLevels,
FSCatalogInfoBitmap whichInfo,
Boolean wantFSSpec,
Boolean wantName,
IterateContainerFilterProcPtr iterateFilter,
void *yourDataPtr);
/*
The FSIterateContainer function performs a recursive iteration (scan) of the
specified container directory and calls your IterateContainerFilterProc
function once for each file and directory found.
The maxLevels parameter lets you control how deep the recursion goes.
If maxLevels is 1, FSIterateContainer only scans the specified directory;
if maxLevels is 2, FSIterateContainer scans the specified directory and
one subdirectory below the specified directory; etc. Set maxLevels to
zero to scan all levels.
The yourDataPtr parameter can point to whatever data structure you might
want to access from within your IterateContainerFilterProc.
container --> The FSRef to the container directory to iterate.
maxLevels --> Maximum number of directory levels to scan or
zero to scan all directory levels.
whichInfo --> The fields of the FSCatalogInfo you wish to get.
wantFSSpec --> Set to true if you want the FSSpec to each
object passed to your IterateContainerFilterProc.
wantName --> Set to true if you want the name of each
object passed to your IterateContainerFilterProc.
iterateFilter --> A pointer to the IterateContainerFilterProc you
want called once for each file and directory found
by FSIterateContainer.
yourDataPtr --> An optional pointer to whatever data structure you
might want to access from within the
IterateFilterProc.
*/
/*****************************************************************************/
#pragma mark FSGetDirectoryItems
OSErr
FSGetDirectoryItems(
const FSRef *container,
FSRef ***refsHandle, /* pointer to handle of FSRefs */
ItemCount *numRefs,
Boolean *containerChanged);
/*
The FSGetDirectoryItems function returns the list of items in the specified
container. The array of FSRef records is returned in a Handle, refsHandle,
which is allocated by FSGetDirectoryItems. The caller is responsible for
disposing of refsHandle if the FSGetDirectoryItems returns noErr.
container --> FSRef to a directory.
refsHandle <-- Pointer to an FSRef Handle where the array of
FSRefs is to be returned.
numRefs <-- The number of FSRefs returned in the array.
containerChanged <-- Set to true if the container changes while the
list of items is being obtained.
*/
/*****************************************************************************/
#pragma mark FSExchangeObjectsCompat
OSErr
FSExchangeObjectsCompat(
const FSRef *sourceRef,
const FSRef *destRef,
FSRef *newSourceRef,
FSRef *newDestRef);
/*
The FSExchangeObjectsCompat function exchanges the data between two files.
The FSExchangeObjectsCompat function is an enhanced version of
FSExchangeObjects function. The two enhancements FSExchangeObjectsCompat
provides are:
1, FSExchangeObjectsCompat will work on volumes which do not support
FSExchangeObjects. FSExchangeObjectsCompat does this by emulating
FSExchangeObjects through a series of File Manager operations. If
there is a failure at any step along the way, FSExchangeObjectsCompat
attempts to undo any steps already taken to leave the files in their
original state in their original locations.
2. FSExchangeObjectsCompat returns new FSRefs to the source and
destination files. Note that if this function fails at any step along
the way, newSourceRef and newDestRef still give you access to the final
locations of the files being exchanged -- even if they are renamed or
not in their original locations.
sourceRef --> FSRef to the source file.
destRef --> FSRef to the destination file.
newSourceRef <-- The new FSRef to the source file.
newDestRef <-- The new FSRef to the destination file.
*/
/*****************************************************************************/
#pragma mark ----- Shared Environment Routines -----
/*****************************************************************************/
#if 0
/* These methods were added in 10.4, and are not used by ResKnife, so we just comment them out to avoid errors */
#pragma mark FSLockRange
OSErr
FSLockRange(
SInt16 refNum,
SInt32 rangeLength,
SInt32 rangeStart);
/*
The LockRange function locks (denies access to) a portion of a file
that was opened with shared read/write permission.
refNum --> The file reference number of an open file.
rangeLength --> The number of bytes in the range.
rangeStart --> The starting byte in the range to lock.
__________
Also see: UnlockRange
*/
/*****************************************************************************/
#pragma mark FSUnlockRange
OSErr
FSUnlockRange(
SInt16 refNum,
SInt32 rangeLength,
SInt32 rangeStart);
/*
The UnlockRange function unlocks (allows access to) a previously locked
portion of a file that was opened with shared read/write permission.
refNum --> The file reference number of an open file.
rangeLength --> The number of bytes in the range.
rangeStart --> The starting byte in the range to unlock.
__________
Also see: LockRange
*/
#endif
/*****************************************************************************/
#pragma mark FSGetDirAccess
OSErr
FSGetDirAccess(
const FSRef *ref,
SInt32 *ownerID, /* can be NULL */
SInt32 *groupID, /* can be NULL */
SInt32 *accessRights); /* can be NULL */
/*
The FSGetDirAccess function retrieves the directory access control
information for a directory on a shared volume.
ref --> An FSRef specifying the directory.
ownerID <** An optional pointer to a SInt32.
If not NULL, the directory's owner ID
will be returned in the SInt32.
groupID <** An optional pointer to a SInt32.
If not NULL, the directory's group ID, or 0
if no group affiliation, will be returned in
the SInt32.
accessRights <** An optional pointer to a SInt32.
If not NULL, the directory's access rights
will be returned in the SInt32.
__________
Also see: FSSetDirAccess, FSMapID, FSMapName
*/
/*****************************************************************************/
#pragma mark FSSetDirAccess
OSErr
FSSetDirAccess(
const FSRef *ref,
SInt32 ownerID,
SInt32 groupID,
SInt32 accessRights);
/*
The FSpSetDirAccess function changes the directory access control
information for a directory on a shared volume. You must be the owner of
a directory to change its access control information.
ref --> An FSRef specifying the directory.
ownerID --> The directory's owner ID.
groupID --> The directory's group ID or 0 if no group affiliation.
accessRights --> The directory's access rights.
__________
Also see: FSGetDirAccess, FSMapID, FSMapName
*/
/*****************************************************************************/
#pragma mark FSGetVolMountInfoSize
OSErr
FSGetVolMountInfoSize(
FSVolumeRefNum volRefNum,
SInt16 *size);
/*
The FSGetVolMountInfoSize function determines the how much space the
program needs to allocate for a volume mounting information record.
volRefNum --> Volume specification.
size <-- The space needed (in bytes) of the volume
mounting information record.
__________
Also see: FSGetVolMountInfo, VolumeMount
*/
/*****************************************************************************/
#pragma mark FSGetVolMountInfo
OSErr
FSGetVolMountInfo(
FSVolumeRefNum volRefNum,
void *volMountInfo);
/*
The FSGetVolMountInfo function retrieves a volume mounting information
record containing all the information needed to mount the volume,
except for passwords.
volRefNum --> Volume specification.
volMountInfo <-- The volume mounting information.
__________
Also see: FSGetVolMountInfoSize, VolumeMount
*/
/*****************************************************************************/
#if 0
/* This method were added in 10.4, and are not used by ResKnife, so we just comment it out to avoid errors */
#pragma mark FSVolumeMount
OSErr
FSVolumeMount(
const void *volMountInfo,
FSVolumeRefNum *volRefNum);
/*
The VolumeMount function mounts a volume using a volume mounting
information record.
volMountInfo --> A volume mounting information record.
volRefNum <-- The volume reference number.
__________
Also see: FSGetVolMountInfoSize, FSGetVolMountInfo
*/
#endif
/*****************************************************************************/
#pragma mark FSMapID
OSErr
FSMapID(
FSVolumeRefNum volRefNum,
SInt32 ugID,
SInt16 objType,
Str31 name);
/*
The FSMapID function determines the name of a user or group if you know
the user or group ID.
volRefNum --> Volume specification.
objType --> The mapping function code:
kOwnerID2Name to map a user ID to a user name
kGroupID2Name to map a group ID to a group name
name <** An optional pointer to a buffer (minimum Str31).
If not NULL, the user or group name
will be returned in the buffer.
__________
Also see: FSGetDirAccess, FSSetDirAccess, FSMapName
*/
/*****************************************************************************/
#pragma mark FSMapName
OSErr
FSMapName(
FSVolumeRefNum volRefNum,
ConstStr255Param name,
SInt16 objType,
SInt32 *ugID);
/*
The FSMapName function determines the user or group ID if you know the
user or group name.
volRefNum --> Volume specification.
name --> The user or group name.
objType --> The mapping function code:
kOwnerName2ID to map a user name to a user ID
kGroupName2ID to map a user name to a group ID
ugID <-- The user or group ID.
__________
Also see: FSGetDirAccess, FSSetDirAccess, FSMapID
*/
/*****************************************************************************/
#pragma mark FSCopyFile
OSErr
FSCopyFile(
const FSRef *srcFileRef,
const FSRef *dstDirectoryRef,
UniCharCount nameLength,
const UniChar *copyName, /* can be NULL (no rename during copy) */
TextEncoding textEncodingHint,
FSRef *newRef); /* can be NULL */
/*
The FSCopyFile function duplicates a file and optionally renames it.
The source and destination volumes must be on the same file server.
This function instructs the server to copy the file.
srcFileRef --> An FSRef specifying the source file.
dstDirectoryRef --> An FSRef specifying the destination directory.
nameLength --> Number of UniChar in copyName parameter (ignored
if copyName is NULL).
copyName --> Points to the new file name if the file is to be
renamed, or NULL if the file isn't to be renamed.
textEncodingHint --> The text encoding hint used for the rename.
You can pass kTextEncodingUnknown to use the
"default" textEncodingHint.
newRef <** An optional pointer to a FSRef.
If not NULL, the FSRef of the duplicated file
will be returned in the FSRef.
*/
/*****************************************************************************/
#pragma mark FSMoveRename
OSErr
FSMoveRename(
const FSRef *srcFileRef,
const FSRef *dstDirectoryRef,
UniCharCount nameLength,
const UniChar *moveName, /* can be NULL (no rename during move) */
TextEncoding textEncodingHint,
FSRef *newRef); /* can be NULL */
/*
The FSMoveRename function moves a file or directory (object), and
optionally renames it. The source and destination locations must be on
the same shared volume.
srcFileRef --> An FSRef specifying the source file.
dstDirectoryRef --> An FSRef specifying the destination directory.
nameLength --> Number of UniChar in moveName parameter (ignored
if copyName is NULL)
moveName --> Points to the new object name if the object is to be
renamed, or NULL if the object isn't to be renamed.
textEncodingHint --> The text encoding hint used for the rename.
You can pass kTextEncodingUnknown to use the
"default" textEncodingHint.
newRef <** An optional pointer to a FSRef.
If not NULL, the FSRef of the moved object
will be returned in the FSRef.
*/
/*****************************************************************************/
#pragma mark ----- File ID Routines -----
/*****************************************************************************/
#pragma mark FSResolveFileIDRef
OSErr
FSResolveFileIDRef(
FSVolumeRefNum volRefNum,
SInt32 fileID,
FSRef *ref);
/*
The FSResolveFileIDRef function returns an FSRef for the file with the
specified file ID reference.
volRefNum --> Volume specification.
fileID --> The file ID reference.
ref <-- The FSRef for the file ID reference.
__________
Also see: FSCreateFileIDRef, FSDeleteFileIDRef
*/
/*****************************************************************************/
#pragma mark FSCreateFileIDRef
OSErr
FSCreateFileIDRef(
const FSRef *ref,
SInt32 *fileID);
/*
The FSCreateFileIDRef function creates a file ID reference for the
specified file, or if a file ID reference already exists, supplies
the file ID reference and returns the result code fidExists or afpIDExists.
ref --> The FSRef for the file.
fileID <-- The file ID reference (if result is noErr,
fidExists, or afpIDExists).
__________
Also see: GetFSRefFromFileIDRef, FSDeleteFileIDRef
*/
/*****************************************************************************/
#pragma mark FSDeleteFileIDRef
/*
Why is there no FSDeleteFileIDRef routine? There are two reasons:
1. Since Mac OS 8.1, PBDeleteFileIDRef hasn't deleted file ID references.
On HFS volumes, deleting a file ID reference breaks aliases (which
use file ID references to track files as they are moved around on a
volume) and file ID references are automatically deleted when the file
they refer to is deleted. On HFS Plus volumes, file ID references are
always created when a file is created, deleted when the file is deleted,
and cannot be deleted at any other time.
2. PBDeleteFileIDRef causes a memory access fault under Mac OS X 10.0
through 10.1.x. While this will be fixed in a future release, the
implementation, like the Mac OS 8/9 implementation, does not delete
file ID references.
__________
Also see: GetFSRefFromFileIDRef, FSCreateFileIDRef
*/
/*****************************************************************************/
#pragma mark ----- Utility Routines -----
/*****************************************************************************/
#pragma mark GetTempBuffer
Ptr
GetTempBuffer(
ByteCount buffReqSize,
ByteCount *buffActSize);
/*
The GetTempBuffer function allocates a temporary buffer for file system
operations which is at least 4K bytes and a multiple of 4K bytes.
buffReqSize --> Size you'd like the buffer to be.
buffActSize <-- The size of the buffer allocated.
function result <-- Pointer to memory allocated, or NULL if no memory
was available. The caller is responsible for
disposing of this buffer with DisposePtr.
*/
/*****************************************************************************/
#pragma mark FileRefNumGetFSRef
OSErr
FileRefNumGetFSRef(
short refNum,
FSRef *ref);
/*
The FileRefNumGetFSRef function gets the FSRef of an open file.
refNum --> The file reference number of an open file.
ref <-- The FSRef to the open file.
*/
/*****************************************************************************/
#pragma mark FSSetDefault
OSErr
FSSetDefault(
const FSRef *newDefault,
FSRef *oldDefault);
/*
The FSSetDefault function sets the current working directory to the
directory specified by newDefault. The previous current working directory
is returned in oldDefault and must be used to restore the current working
directory to its previous state with the FSRestoreDefault function.
These two functions are designed to be used as a wrapper around
Standard I/O routines where the location of the file is implied to be the
current working directory. This is how you should use these functions:
result = FSSetDefault(&newDefault, &oldDefault);
if ( noErr == result )
{
// call the Stdio functions like remove, rename,
// fopen, freopen, etc here!
result = FSRestoreDefault(&oldDefault);
}
newDefault --> An FSRef that specifies the new current working
directory.
oldDefault <-- The previous current working directory's FSRef.
__________
Also see: FSRestoreDefault
*/
/*****************************************************************************/
#pragma mark FSRestoreDefault
OSErr
FSRestoreDefault(
const FSRef *oldDefault);
/*
The FSRestoreDefault function restores the current working directory
to the directory specified by oldDefault. The oldDefault parameter was
previously obtained from the FSSetDefault function.
These two functions are designed to be used as a wrapper around
Standard I/O routines where the location of the file is implied to be the
current working directory. This is how you should use these functions:
result = FSSetDefault(&newDefault, &oldDefault);
if ( noErr == result )
{
// call the Stdio functions like remove, rename,
// fopen, freopen, etc here!
result = FSRestoreDefault(&oldDefault);
}
oldDefault --> The FSRef of the location to restore.
__________
Also see: FSSetDefault
*/
/*****************************************************************************/
#if PRAGMA_STRUCT_ALIGN
#pragma options align=reset
#elif PRAGMA_STRUCT_PACKPUSH
#pragma pack(pop)
#elif PRAGMA_STRUCT_PACK
#pragma pack()
#endif
#ifdef PRAGMA_IMPORT_OFF
#pragma import off
#elif PRAGMA_IMPORT
#pragma import reset
#endif
#ifdef __cplusplus
}
#endif
#endif /* __MOREFILESX__ */
\ No newline at end of file
+/*
File: MoreFilesX.h
Contains: A collection of useful high-level File Manager routines
which use the HFS Plus APIs wherever possible.
Version: MoreFilesX 1.0
Copyright: Š 1992-2002 by Apple Computer, Inc., all rights reserved.
You may incorporate this sample code into your applications without
restriction, though the sample code has been provided "AS IS" and the
responsibility for its operation is 100% yours. However, what you are
not permitted to do is to redistribute the source as "DSC Sample Code"
after having made changes. If you're going to re-distribute the source,
we require that you make it clear in the source that the code was
descended from Apple Sample Code, but that you've made changes.
File Ownership:
DRI: Apple Macintosh Developer Technical Support
Other Contact: For bug reports, consult the following page on
the World Wide Web:
http://developer.apple.com/bugreporter/
Technology: DTS Sample Code
Writers:
(JL) Jim Luther
Change History (most recent first):
<1> 1/25/02 JL MoreFilesX 1.0
Notes:
What do those arrows in the documentation for each routine mean?
--> The parameter is an input
<-- The parameter is an output. The pointer to the variable
where the output will be returned (must not be NULL).
<** The parameter is an optional output. If it is not a
NULL pointer, it points to the variable where the output
will be returned. If it is a NULL pointer, the output will
not be returned and will possibly let the routine and the
File Manager do less work. If you don't need an optional output,
don't ask for it.
**> The parameter is an optional input. If it is not a
NULL pointer, it points to the variable containing the
input data. If it is a NULL pointer, the input is not used
and will possibly let the routine and the File Manager
do less work.
*/
#ifndef __MOREFILESX__
#define __MOREFILESX__
#ifndef __MACTYPES__
#include
#endif
#ifndef __FINDER__
#include
#endif
#ifndef __FILES__
#include
#endif
#ifndef __TEXTCOMMON__
#include
#endif
#if PRAGMA_ONCE
#pragma once
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if PRAGMA_IMPORT
#pragma import on
#endif
#if PRAGMA_STRUCT_ALIGN
#pragma options align=mac68k
#elif PRAGMA_STRUCT_PACKPUSH
#pragma pack(push, 2)
#elif PRAGMA_STRUCT_PACK
#pragma pack(2)
#endif
/*****************************************************************************/
#pragma mark ----- FinderInfo and ExtendedFinderInfo -----
/*
* FSGetFinderInfo and FSSetFinderInfo use these unions for Finder information.
*/
union FinderInfo
{
FileInfo file;
FolderInfo folder;
};
typedef union FinderInfo FinderInfo;
union ExtendedFinderInfo
{
ExtendedFileInfo file;
ExtendedFolderInfo folder;
};
typedef union ExtendedFinderInfo ExtendedFinderInfo;
/*****************************************************************************/
#pragma mark ----- GetVolParmsInfoBuffer Macros -----
/*
* Macros to get information out of GetVolParmsInfoBuffer.
*/
/* version 1 field getters */
#define GetVolParmsInfoVersion(volParms) \
((volParms)->vMVersion)
#define GetVolParmsInfoAttrib(volParms) \
((volParms)->vMAttrib)
#define GetVolParmsInfoLocalHand(volParms) \
((volParms)->vMLocalHand)
#define GetVolParmsInfoServerAdr(volParms) \
((volParms)->vMServerAdr)
/* version 2 field getters (assume zero result if version < 2) */
#define GetVolParmsInfoVolumeGrade(volParms) \
(((volParms)->vMVersion >= 2) ? (volParms)->vMVolumeGrade : 0)
#define GetVolParmsInfoForeignPrivID(volParms) \
(((volParms)->vMVersion >= 2) ? (volParms)->vMForeignPrivID : 0)
/* version 3 field getters (assume zero result if version < 3) */
#define GetVolParmsInfoExtendedAttributes(volParms) \
(((volParms)->vMVersion >= 3) ? (volParms)->vMExtendedAttributes : 0)
/* attribute bits supported by all versions of GetVolParmsInfoBuffer */
#define VolIsNetworkVolume(volParms) \
((volParms)->vMServerAdr != 0)
#define VolHasLimitFCBs(volParms) \
(((volParms)->vMAttrib & (1L << bLimitFCBs)) != 0)
#define VolHasLocalWList(volParms) \
(((volParms)->vMAttrib & (1L << bLocalWList)) != 0)
#define VolHasNoMiniFndr(volParms) \
(((volParms)->vMAttrib & (1L << bNoMiniFndr)) != 0)
#define VolHasNoVNEdit(volParms) \
(((volParms)->vMAttrib & (1L << bNoVNEdit)) != 0)
#define VolHasNoLclSync(volParms) \
(((volParms)->vMAttrib & (1L << bNoLclSync)) != 0)
#define VolHasTrshOffLine(volParms) \
(((volParms)->vMAttrib & (1L << bTrshOffLine)) != 0)
#define VolHasNoSwitchTo(volParms) \
(((volParms)->vMAttrib & (1L << bNoSwitchTo)) != 0)
#define VolHasNoDeskItems(volParms) \
(((volParms)->vMAttrib & (1L << bNoDeskItems)) != 0)
#define VolHasNoBootBlks(volParms) \
(((volParms)->vMAttrib & (1L << bNoBootBlks)) != 0)
#define VolHasAccessCntl(volParms) \
(((volParms)->vMAttrib & (1L << bAccessCntl)) != 0)
#define VolHasNoSysDir(volParms) \
(((volParms)->vMAttrib & (1L << bNoSysDir)) != 0)
#define VolHasExtFSVol(volParms) \
(((volParms)->vMAttrib & (1L << bHasExtFSVol)) != 0)
#define VolHasOpenDeny(volParms) \
(((volParms)->vMAttrib & (1L << bHasOpenDeny)) != 0)
#define VolHasCopyFile(volParms) \
(((volParms)->vMAttrib & (1L << bHasCopyFile)) != 0)
#define VolHasMoveRename(volParms) \
(((volParms)->vMAttrib & (1L << bHasMoveRename)) != 0)
#define VolHasDesktopMgr(volParms) \
(((volParms)->vMAttrib & (1L << bHasDesktopMgr)) != 0)
#define VolHasShortName(volParms) \
(((volParms)->vMAttrib & (1L << bHasShortName)) != 0)
#define VolHasFolderLock(volParms) \
(((volParms)->vMAttrib & (1L << bHasFolderLock)) != 0)
#define VolHasPersonalAccessPrivileges(volParms) \
(((volParms)->vMAttrib & (1L << bHasPersonalAccessPrivileges)) != 0)
#define VolHasUserGroupList(volParms) \
(((volParms)->vMAttrib & (1L << bHasUserGroupList)) != 0)
#define VolHasCatSearch(volParms) \
(((volParms)->vMAttrib & (1L << bHasCatSearch)) != 0)
#define VolHasFileIDs(volParms) \
(((volParms)->vMAttrib & (1L << bHasFileIDs)) != 0)
#define VolHasBTreeMgr(volParms) \
(((volParms)->vMAttrib & (1L << bHasBTreeMgr)) != 0)
#define VolHasBlankAccessPrivileges(volParms) \
(((volParms)->vMAttrib & (1L << bHasBlankAccessPrivileges)) != 0)
#define VolSupportsAsyncRequests(volParms) \
(((volParms)->vMAttrib & (1L << bSupportsAsyncRequests)) != 0)
#define VolSupportsTrashVolumeCache(volParms) \
(((volParms)->vMAttrib & (1L << bSupportsTrashVolumeCache)) != 0)
/* attribute bits supported by version 3 and greater versions of GetVolParmsInfoBuffer */
#define VolIsEjectable(volParms) \
((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bIsEjectable)) != 0)
#define VolSupportsHFSPlusAPIs(volParms) \
((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsHFSPlusAPIs)) != 0)
#define VolSupportsFSCatalogSearch(volParms) \
((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsFSCatalogSearch)) != 0)
#define VolSupportsFSExchangeObjects(volParms) \
((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsFSExchangeObjects)) != 0)
#define VolSupports2TBFiles(volParms) \
((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupports2TBFiles)) != 0)
#define VolSupportsLongNames(volParms) \
((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsLongNames)) != 0)
#define VolSupportsMultiScriptNames(volParms) \
((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsMultiScriptNames)) != 0)
#define VolSupportsNamedForks(volParms) \
((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsNamedForks)) != 0)
#define VolSupportsSubtreeIterators(volParms) \
((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsSubtreeIterators)) != 0)
#define VolL2PCanMapFileBlocks(volParms) \
((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bL2PCanMapFileBlocks)) != 0)
#define VolParentModDateChanges(volParms) \
((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bParentModDateChanges)) != 0)
#define VolAncestorModDateChanges(volParms) \
((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bAncestorModDateChanges)) != 0)
#define VolSupportsSymbolicLinks(volParms) \
((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsSymbolicLinks)) != 0)
#define VolIsAutoMounted(volParms) \
((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bIsAutoMounted)) != 0)
/*****************************************************************************/
#pragma mark ----- userPrivileges Bit Masks and Macros -----
/*
* Bit masks and macros to get common information out of userPrivileges byte
* returned by FSGetCatalogInfo.
*
* Note: The userPrivileges byte is the same as the ioACUser byte returned
* by PBGetCatInfo, and is the 1's complement of the user's privileges
* byte returned in ioACAccess by PBHGetDirAccess. That's where the
* ioACUser names came from.
*
* The userPrivileges are user's effective privileges based on the
* user ID and the groups that user belongs to, and the owner, group,
* and everyone privileges for the given directory.
*/
enum
{
/* mask for just the access restriction bits */
kioACUserAccessMask = (kioACUserNoSeeFolderMask +
kioACUserNoSeeFilesMask +
kioACUserNoMakeChangesMask),
/* common access privilege settings */
kioACUserFull = 0x00, /* no access restiction bits on */
kioACUserNone = kioACUserAccessMask, /* all access restiction bits on */
kioACUserDropBox = (kioACUserNoSeeFolderMask +
kioACUserNoSeeFilesMask), /* make changes, but not see files or folders */
kioACUserBulletinBoard = kioACUserNoMakeChangesMask /* see files and folders, but not make changes */
};
/* Macros for testing ioACUser bits. */
#define UserIsOwner(userPrivileges) \
(((userPrivileges) & kioACUserNotOwnerMask) == 0)
#define UserHasFullAccess(userPrivileges) \
(((userPrivileges) & (kioACUserAccessMask)) == kioACUserFull)
#define UserHasDropBoxAccess(userPrivileges) \
(((userPrivileges) & kioACUserAccessMask) == kioACUserDropBox)
#define UserHasBulletinBoard(userPrivileges) \
(((userPrivileges) & kioACUserAccessMask) == kioACUserBulletinBoard)
#define UserHasNoAccess(userPrivileges) \
(((userPrivileges) & kioACUserAccessMask) == kioACUserNone)
/*****************************************************************************/
#pragma mark ----- File Access Routines -----
/*****************************************************************************/
#pragma mark FSCopyFork
OSErr
FSCopyFork(
SInt16 srcRefNum,
SInt16 dstRefNum,
void *copyBufferPtr,
ByteCount copyBufferSize);
/*
The FSCopyFork function copies all data from the source fork to the
destination fork of open file forks and makes sure the destination EOF
is equal to the source EOF.
srcRefNum --> The source file reference number.
dstRefNum --> The destination file reference number.
copyBufferPtr --> Pointer to buffer to use during copy. The
buffer should be at least 4K-bytes minimum.
The larger the buffer, the faster the copy
(up to a point).
copyBufferSize --> The size of the copy buffer.
*/
/*****************************************************************************/
#pragma mark ----- Volume Access Routines -----
/*****************************************************************************/
#pragma mark FSGetVolParms
OSErr
FSGetVolParms(
FSVolumeRefNum volRefNum,
UInt32 bufferSize,
GetVolParmsInfoBuffer *volParmsInfo,
UInt32 *actualInfoSize);
/*
The FSGetVolParms function returns information about the characteristics
of a volume. A result of paramErr usually just means the volume doesn't
support GetVolParms and the feature you were going to check
for isn't available.
volRefNum --> Volume specification.
bufferSize --> Size of buffer pointed to by volParmsInfo.
volParmsInfo <-- A GetVolParmsInfoBuffer record where the volume
attributes information is returned.
actualInfoSize <-- The number of bytes actually returned
in volParmsInfo.
__________
Also see: The GetVolParmsInfoBuffer Macros for checking attribute bits
in this file
*/
/*****************************************************************************/
#pragma mark FSGetVRefNum
OSErr
FSGetVRefNum(
const FSRef *ref,
FSVolumeRefNum *vRefNum);
/*
The FSGetVRefNum function determines the volume reference
number of a volume from a FSRef.
ref --> The FSRef.
vRefNum <-- The volume reference number.
*/
/*****************************************************************************/
#pragma mark FSGetVInfo
OSErr
FSGetVInfo(
FSVolumeRefNum volume,
HFSUniStr255 *volumeName, /* can be NULL */
UInt64 *freeBytes, /* can be NULL */
UInt64 *totalBytes); /* can be NULL */
/*
The FSGetVInfo function returns the name, available space (in bytes),
and total space (in bytes) for the specified volume.
volume --> The volume reference number.
volumeName <** An optional pointer to a HFSUniStr255.
If not NULL, the volume name will be returned in
the HFSUniStr255.
freeBytes <** An optional pointer to a UInt64.
If not NULL, the number of free bytes on the
volume will be returned in the UInt64.
totalBytes <** An optional pointer to a UInt64.
If not NULL, the total number of bytes on the
volume will be returned in the UInt64.
*/
/*****************************************************************************/
#pragma mark FSGetVolFileSystemID
OSErr
FSGetVolFileSystemID(
FSVolumeRefNum volume,
UInt16 *fileSystemID, /* can be NULL */
UInt16 *signature); /* can be NULL */
/*
The FSGetVolFileSystemID function returns the file system ID and signature
of a mounted volume. The file system ID identifies the file system
that handles requests to a particular volume. The signature identifies the
volume type of the volume (for example, FSID 0 is Macintosh HFS Plus, HFS
or MFS, where a signature of 0x4244 identifies the volume as HFS).
Here's a partial list of file system ID numbers (only Apple's file systems
are listed):
FSID File System
----- -----------------------------------------------------
$0000 Macintosh HFS Plus, HFS or MFS
$0100 ProDOS File System
$0101 PowerTalk Mail Enclosures
$4147 ISO 9660 File Access (through Foreign File Access)
$4242 High Sierra File Access (through Foreign File Access)
$464D QuickTake File System (through Foreign File Access)
$4953 Macintosh PC Exchange (MS-DOS)
$4A48 Audio CD Access (through Foreign File Access)
$4D4B Apple Photo Access (through Foreign File Access)
$6173 AppleShare (later versions of AppleShare only)
See the Technical Note "FL 35 - Determining Which File System
Is Active" and the "Guide to the File System Manager" for more
information.
volume --> The volume reference number.
fileSystemID <** An optional pointer to a UInt16.
If not NULL, the volume's file system ID will
be returned in the UInt16.
signature <** An optional pointer to a UInt16.
If not NULL, the volume's signature will
be returned in the UInt16.
*/
/*****************************************************************************/
#pragma mark FSGetMountedVolumes
OSErr
FSGetMountedVolumes(
FSRef ***volumeRefsHandle, /* pointer to handle of FSRefs */
ItemCount *numVolumes);
/*
The FSGetMountedVolumes function returns the list of volumes currently
mounted in an array of FSRef records. The array of FSRef records is
returned in a Handle, volumeRefsHandle, which is allocated by
FSGetMountedVolumes. The caller is responsible for disposing of
volumeRefsHandle if the FSGetMountedVolumes returns noErr.
volumeRefsHandle <-- Pointer to an FSRef Handle where the array of
FSRefs is to be returned.
numVolumes <-- The number of volumes returned in the array.
*/
/*****************************************************************************/
#pragma mark ----- FSRef/FSpec/Path/Name Conversion Routines -----
/*****************************************************************************/
#pragma mark FSRefMakeFSSpec
OSErr
FSRefMakeFSSpec(
const FSRef *ref,
FSSpec *spec);
/*
The FSRefMakeFSSpec function returns an FSSpec for the file or
directory specified by the ref parameter.
ref --> An FSRef specifying the file or directory.
spec <-- The FSSpec.
*/
/*****************************************************************************/
#pragma mark FSMakeFSRef
OSErr
FSMakeFSRef(
FSVolumeRefNum volRefNum,
SInt32 dirID,
ConstStr255Param name,
FSRef *ref);
/*
The FSMakeFSRef function creates an FSRef from the traditional
volume reference number, directory ID and pathname inputs. It is
functionally equivalent to FSMakeFSSpec followed by FSpMakeFSRef.
volRefNum --> Volume specification.
dirID --> Directory specification.
name --> The file or directory name, or NULL.
ref <-- The FSRef.
*/
/*****************************************************************************/
#pragma mark FSMakePath
OSStatus
FSMakePath(
SInt16 vRefNum,
SInt32 dirID,
ConstStr255Param name,
UInt8 *path,
UInt32 maxPathSize);
/*
The FSMakePath function creates a pathname from the traditional volume reference
number, directory ID, and pathname inputs. It is functionally equivalent to
FSMakeFSSpec, FSpMakeFSRef, FSRefMakePath.
volRefNum --> Volume specification.
dirID --> Directory specification.
name --> The file or directory name, or NULL.
path <-- A pointer to a buffer which FSMakePath will
fill with a C string representing the pathname
to the file or directory specified. The format of
the pathname returned can be determined with the
Gestalt selector gestaltFSAttr's
gestaltFSUsesPOSIXPathsForConversion bit.
If the gestaltFSUsesPOSIXPathsForConversion bit is
clear, the pathname is a Mac OS File Manager full
pathname in a C string, and file or directory names
in the pathname may be mangled as returned by
the File Manager. If the
gestaltFSUsesPOSIXPathsForConversion bit is set,
the pathname is a UTF8 encoded POSIX absolute
pathname in a C string. In either case, the
pathname returned can be passed back to
FSPathMakeRef to create an FSRef to the file or
directory, or FSPathMakeFSSpec to craete an FSSpec
to the file or directory.
maxPathSize --> The size of the path buffer in bytes. If the path
buffer is too small for the pathname string,
FSMakePath returns pathTooLongErr or
buffersTooSmall.
*/
/*****************************************************************************/
#pragma mark FSPathMakeFSSpec
OSStatus
FSPathMakeFSSpec(
const UInt8 *path,
FSSpec *spec,
Boolean *isDirectory); /* can be NULL */
/*
The FSPathMakeFSSpec function converts a pathname to an FSSpec.
path --> A pointer to a C String that is the pathname. The
format of the pathname you must supply can be
determined with the Gestalt selector gestaltFSAttr's
gestaltFSUsesPOSIXPathsForConversion bit.
If the gestaltFSUsesPOSIXPathsForConversion bit is
clear, the pathname must be a Mac OS File Manager
full pathname in a C string. If the
gestaltFSUsesPOSIXPathsForConversion bit is set,
the pathname must be a UTF8 encoded POSIX absolute
pathname in a C string.
spec <-- The FSSpec.
isDirectory <** An optional pointer to a Boolean.
If not NULL, true will be returned in the Boolean
if the specified path is a directory, or false will
be returned in the Boolean if the specified path is
a file.
*/
/*****************************************************************************/
#pragma mark UnicodeNameGetHFSName
OSErr
UnicodeNameGetHFSName(
UniCharCount nameLength,
const UniChar *name,
TextEncoding textEncodingHint,
Boolean isVolumeName,
Str31 hfsName);
/*
The UnicodeNameGetHFSName function converts a Unicode string
to a Pascal Str31 (or Str27) string using an algorithm similar to that used
by the File Manager. Note that if the name is too long or cannot be converted
using the given text encoding hint, you will get an error instead of the
mangled name that the File Manager would return.
nameLength --> Number of UniChar in name parameter.
name --> The Unicode string to convert.
textEncodingHint --> The text encoding hint used for the conversion.
You can pass kTextEncodingUnknown to use the
"default" textEncodingHint.
isVolumeName --> If true, the output name will be limited to
27 characters (kHFSMaxVolumeNameChars). If false,
the output name will be limited to 31 characters
(kHFSMaxFileNameChars).
hfsName <-- The hfsName as a Pascal string.
__________
Also see: HFSNameGetUnicodeName
*/
/*****************************************************************************/
#pragma mark HFSNameGetUnicodeName
OSErr
HFSNameGetUnicodeName(
ConstStr31Param hfsName,
TextEncoding textEncodingHint,
HFSUniStr255 *unicodeName);
/*
The HFSNameGetUnicodeName function converts a Pascal Str31 string to an
Unicode HFSUniStr255 string using the same routines as the File Manager.
hfsName --> The Pascal string to convert.
textEncodingHint --> The text encoding hint used for the conversion.
You can pass kTextEncodingUnknown to use the
"default" textEncodingHint.
unicodeName <-- The Unicode string.
__________
Also see: UnicodeNameGetHFSName
*/
/*****************************************************************************/
#pragma mark ----- File/Directory Manipulation Routines -----
/*****************************************************************************/
#pragma mark FSRefValid
Boolean FSRefValid(const FSRef *ref);
/*
The FSRefValid function determines if an FSRef is valid. If the result is
true, then the FSRef refers to an existing file or directory.
ref --> FSRef to a file or directory.
*/
/*****************************************************************************/
#pragma mark FSGetParentRef
OSErr
FSGetParentRef(
const FSRef *ref,
FSRef *parentRef);
/*
The FSGetParentRef function gets the parent directory FSRef of the
specified object.
Note: FSRefs always point to real file system objects. So, there cannot
be a FSRef to the parent of volume root directories. If you call
FSGetParentRef with a ref to the root directory of a volume, the
function result will be noErr and the parentRef will be invalid (using it
for other file system requests will fail).
ref --> FSRef to a file or directory.
parentRef <-- The parent directory's FSRef.
*/
/*****************************************************************************/
#pragma mark FSGetFileDirName
OSErr
FSGetFileDirName(
const FSRef *ref,
HFSUniStr255 *outName);
/*
The FSGetFileDirName function gets the name of the file or directory
specified.
ref --> FSRef to a file or directory.
outName <-- The file or directory name.
*/
/*****************************************************************************/
#pragma mark FSGetNodeID
OSErr
FSGetNodeID(
const FSRef *ref,
long *nodeID, /* can be NULL */
Boolean *isDirectory); /* can be NULL */
/*
The GetNodeIDFromFSRef function gets the node ID number of the
file or directory specified (note: the node ID is the directory ID
for directories).
ref --> FSRef to a file or directory.
nodeID <** An optional pointer to a long.
If not NULL, the node ID will be returned in
the long.
isDirectory <** An optional pointer to a Boolean.
If not NULL, true will be returned in the Boolean
if the object is a directory, or false will be
returned in the Boolean if object is a file.
*/
/*****************************************************************************/
#pragma mark FSGetUserPrivilegesPermissions
OSErr
FSGetUserPrivilegesPermissions(
const FSRef *ref,
UInt8 *userPrivileges, /* can be NULL */
UInt32 permissions[4]); /* can be NULL */
/*
The FSGetUserPrivilegesPermissions function gets the userPrivileges and/or
permissions of the file or directory specified.
ref --> FSRef to a file or directory.
userPrivileges <** An optional pointer to a UInt8.
If not NULL, the userPrivileges will be returned
in the UInt8.
permissions <** An optional pointer to an UInt32[4] array.
If not NULL, the permissions will be returned
in the UInt32[4] array.
*/
/*****************************************************************************/
#pragma mark FSCheckLock
OSErr
FSCheckLock(
const FSRef *ref);
/*
The FSCheckLock function determines if a file or directory is locked.
If FSCheckLock returns noErr, then the file or directory is not locked
and the volume it is on is not locked either. If FSCheckLock returns
fLckdErr, then the file or directory is locked. If FSCheckLock returns
wPrErr, then the volume is locked by hardware (i.e., locked tab on
removable media). If FSCheckLock returns vLckdErr, then the volume is
locked by software.
ref --> FSRef to a file or directory.
*/
/*****************************************************************************/
#pragma mark FSGetForkSizes
OSErr
FSGetForkSizes(
const FSRef *ref,
UInt64 *dataLogicalSize, /* can be NULL */
UInt64 *rsrcLogicalSize); /* can be NULL */
/*
The FSGetForkSizes returns the size of the data and/or resource fork for
the specified file.
ref --> FSRef to a file or directory.
dataLogicalSize <** An optional pointer to a UInt64.
If not NULL, the data fork's size will be
returned in the UInt64.
rsrcLogicalSize <** An optional pointer to a UInt64.
If not NULL, the resource fork's size will be
returned in the UInt64.
__________
Also see: FSGetTotalForkSizes
*/
/*****************************************************************************/
#pragma mark FSGetTotalForkSizes
OSErr
FSGetTotalForkSizes(
const FSRef *ref,
UInt64 *totalLogicalSize, /* can be NULL */
UInt64 *totalPhysicalSize, /* can be NULL */
ItemCount *forkCount); /* can be NULL */
/*
The FSGetTotalForkSizes returns the total logical size and/or the total
physical size of the specified file (i.e., it adds the sizes of all file
forks). It optionally returns the number of file forks.
ref --> FSRef to a file or directory.
totalLogicalSize <** An optional pointer to a UInt64.
If not NULL, the sum of all fork logical sizes
will be returned in the UInt64.
totalPhysicalSize <** An optional pointer to a UInt64.
If not NULL, the sum of all fork physical sizes
will be returned in the UInt64.
forkCount <** An optional pointer to a ItemCount.
If not NULL, the number of file forks
will be returned in the ItemCount.
__________
Also see: FSGetForkSizes
*/
/*****************************************************************************/
#pragma mark FSBumpDate
OSErr
FSBumpDate(
const FSRef *ref);
/*
The FSBumpDate function changes the content modification date of a file
or directory to the current date/time. If the content modification date
is already equal to the current date/time, then add one second to the
content modification date.
ref --> FSRef to a file or directory.
*/
/*****************************************************************************/
#pragma mark FSGetFinderInfo
OSErr
FSGetFinderInfo(
const FSRef *ref,
FinderInfo *info, /* can be NULL */
ExtendedFinderInfo *extendedInfo, /* can be NULL */
Boolean *isDirectory); /* can be NULL */
/*
The FSGetFinderInfo function gets the finder information for a file or
directory.
ref --> FSRef to a file or directory.
info <** An optional pointer to a FinderInfo.
If not NULL, the FileInfo (if ref is a file) or
the FolderInfo (if ref is a folder) will be
returned in the FinderInfo.
extendedInfo <** An optional pointer to a ExtendedFinderInfo.
If not NULL, the ExtendedFileInfo (if ref is a file)
or the ExtendedFolderInfo (if ref is a folder) will
be returned in the ExtendedFinderInfo.
isDirectory <** An optional pointer to a Boolean.
If not NULL, true will be returned in the Boolean
if the object is a directory, or false will be
returned in the Boolean if object is a file.
__________
Also see: FSSetFinderInfo
*/
/*****************************************************************************/
#pragma mark FSSetFinderInfo
OSErr
FSSetFinderInfo(
const FSRef *ref,
const FinderInfo *info, /* can be NULL */
const ExtendedFinderInfo *extendedInfo); /* can be NULL */
/*
The FSSetFinderInfo function sets the finder information for a file or
directory.
ref --> FSRef to a file or directory.
info **> A pointer to a FinderInfo record with the new
FileInfo (if ref is a file) or new FolderInfo
(if ref is a folder), or NULL if the FinderInfo
is not to be changed.
extendedInfo **> A pointer to a FinderInfo record with the new
ExtendedFileInfo (if ref is a file) or new
ExtendedFolderInfo (if ref is a folder), or NULL
if the ExtendedFinderInfo is not to be changed.
__________
Also see: FSGetFinderInfo
*/
/*****************************************************************************/
#pragma mark FSChangeCreatorType
OSErr
FSChangeCreatorType(
const FSRef *ref,
OSType fileCreator,
OSType fileType);
/*
The FSChangeCreatorType function changes the creator and/or file type of a file.
ref --> FSRef to a file.
creator --> The new creator type or 0x00000000 to leave
the creator type alone.
fileType --> The new file type or 0x00000000 to leave the
file type alone.
*/
/*****************************************************************************/
#pragma mark FSChangeFinderFlags
OSErr
FSChangeFinderFlags(
const FSRef *ref,
Boolean setBits,
UInt16 flagBits);
/*
The FSChangeFinderFlags function sets or clears flag bits in
the finderFlags field of a file's FileInfo record or a
directory's FolderInfo record.
ref --> FSRef to a file or directory.
setBits --> If true, then set the bits specified in flagBits.
If false, then clear the bits specified in flagBits.
flagBits --> The flagBits parameter specifies which Finder Flag
bits to set or clear. If a bit in flagBits is set,
then the same bit in fdFlags is either set or
cleared depending on the state of the setBits
parameter.
*/
/*****************************************************************************/
#pragma mark FSSetInvisible
OSErr
FSSetInvisible(
const FSRef *ref);
#pragma mark FSClearInvisible
OSErr
FSClearInvisible(
const FSRef *ref);
/*
The FSSetInvisible and FSClearInvisible functions set or clear the
kIsInvisible bit in the finderFlags field of the specified file or
directory's finder information.
ref --> FSRef to a file or directory.
*/
/*****************************************************************************/
#pragma mark FSSetNameLocked
OSErr
FSSetNameLocked(
const FSRef *ref);
#pragma mark FSClearNameLocked
OSErr
FSClearNameLocked(
const FSRef *ref);
/*
The FSSetNameLocked and FSClearNameLocked functions set or clear the
kNameLocked bit bit in the finderFlags field of the specified file or
directory's finder information.
ref --> FSRef to a file or directory.
*/
/*****************************************************************************/
#pragma mark FSSetIsStationery
OSErr
FSSetIsStationery(
const FSRef *ref);
#pragma mark FSClearIsStationery
OSErr
FSClearIsStationery(
const FSRef *ref);
/*
The FSSetIsStationery and FSClearIsStationery functions set or clear the
kIsStationery bit bit in the finderFlags field of the specified file or
directory's finder information.
ref --> FSRef to a file or directory.
*/
/*****************************************************************************/
#pragma mark FSSetHasCustomIcon
OSErr
FSSetHasCustomIcon(
const FSRef *ref);
#pragma mark FSClearHasCustomIcon
OSErr
FSClearHasCustomIcon(
const FSRef *ref);
/*
The FSSetHasCustomIcon and FSClearHasCustomIcon functions set or clear the
kHasCustomIcon bit bit in the finderFlags field of the specified file or
directory's finder information.
ref --> FSRef to a file or directory.
*/
/*****************************************************************************/
#pragma mark FSClearHasBeenInited
OSErr
FSClearHasBeenInited(
const FSRef *ref);
/*
The FSClearHasBeenInited function clears the kHasBeenInited bit in the
finderFlags field of the specified file or directory's finder information.
Note: There is no FSSetHasBeenInited function because ONLY the Finder
should set the kHasBeenInited bit.
ref --> FSRef to a file or directory.
*/
/*****************************************************************************/
#pragma mark FSCopyFileMgrAttributes
OSErr
FSCopyFileMgrAttributes(
const FSRef *sourceRef,
const FSRef *destinationRef,
Boolean copyLockBit);
/*
The CopyFileMgrAttributes function copies all File Manager attributes
from the source file or directory to the destination file or directory.
If copyLockBit is true, then set the locked state of the destination
to match the source.
sourceRef --> FSRef to a file or directory.
destinationRef --> FSRef to a file or directory.
copyLockBit --> If true, set the locked state of the destination
to match the source.
*/
/*****************************************************************************/
#pragma mark FSMoveRenameObjectUnicode
OSErr
FSMoveRenameObjectUnicode(
const FSRef *ref,
const FSRef *destDirectory,
UniCharCount nameLength,
const UniChar *name, /* can be NULL (no rename during move) */
TextEncoding textEncodingHint,
FSRef *newRef); /* if function fails along the way, newRef is final location of file */
/*
The FSMoveRenameObjectUnicode function moves a file or directory and
optionally renames it. The source and destination locations must be on
the same volume.
Note: If the input ref parameter is invalid, this call will fail and
newRef, like ref, will be invalid.
ref --> FSRef to a file or directory.
destDirectory --> FSRef to the destination directory.
nameLength --> Number of UniChar in name parameter.
name --> An Unicode string with the new name for the
moved object, or NULL if no rename is wanted.
textEncodingHint --> The text encoding hint used for the rename.
You can pass kTextEncodingUnknown to use the
"default" textEncodingHint.
newRef <-- The new FSRef of the object moved. Note that if
this function fails at any step along the way,
newRef is still then final location of the object.
*/
/*****************************************************************************/
#pragma mark FSDeleteContainerContents
OSErr
FSDeleteContainerContents(
const FSRef *container);
/*
The FSDeleteContainerContents function deletes the contents of a container
directory. All files and subdirectories in the specified container are
deleted. If a locked file or directory is encountered, it is unlocked and
then deleted. If any unexpected errors are encountered,
FSDeleteContainerContents quits and returns to the caller.
container --> FSRef to a directory.
__________
Also see: FSDeleteContainer
*/
/*****************************************************************************/
#pragma mark FSDeleteContainer
OSErr
FSDeleteContainer(
const FSRef *container);
/*
The FSDeleteContainer function deletes a container directory and its contents.
All files and subdirectories in the specified container are deleted.
If a locked file or directory is encountered, it is unlocked and then
deleted. After deleting the container's contents, the container is
deleted. If any unexpected errors are encountered, FSDeleteContainer
quits and returns to the caller.
container --> FSRef to a directory.
__________
Also see: FSDeleteContainerContents
*/
/*****************************************************************************/
#pragma mark IterateContainerFilterProcPtr
typedef CALLBACK_API( Boolean , IterateContainerFilterProcPtr ) (
Boolean containerChanged,
ItemCount currentLevel,
const FSCatalogInfo *catalogInfo,
const FSRef *ref,
const FSSpec *spec,
const HFSUniStr255 *name,
void *yourDataPtr);
/*
This is the prototype for the IterateContainerFilterProc function which
is called once for each file and directory found by FSIterateContainer.
The IterateContainerFilterProc can use the read-only data it receives for
whatever it wants.
The result of the IterateContainerFilterProc function indicates if
iteration should be stopped. To stop iteration, return true; to continue
iteration, return false.
The yourDataPtr parameter can point to whatever data structure you might
want to access from within the IterateContainerFilterProc.
containerChanged --> Set to true if the container's contents changed
during iteration.
currentLevel --> The current recursion level into the container.
1 = the container, 2 = the container's immediate
subdirectories, etc.
catalogInfo --> The catalog information for the current object.
Only the fields requested by the whichInfo
parameter passed to FSIterateContainer are valid.
ref --> The FSRef to the current object.
spec --> The FSSpec to the current object if the wantFSSpec
parameter passed to FSIterateContainer is true.
name --> The name of the current object if the wantName
parameter passed to FSIterateContainer is true.
yourDataPtr --> An optional pointer to whatever data structure you
might want to access from within the
IterateFilterProc.
result <-- To stop iteration, return true; to continue
iteration, return false.
__________
Also see: FSIterateContainer
*/
/*****************************************************************************/
#pragma mark CallIterateContainerFilterProc
#define CallIterateContainerFilterProc(userRoutine, containerChanged, currentLevel, catalogInfo, ref, spec, name, yourDataPtr) \
(*(userRoutine))((containerChanged), (currentLevel), (catalogInfo), (ref), (spec), (name), (yourDataPtr))
/*****************************************************************************/
#pragma mark FSIterateContainer
OSErr
FSIterateContainer(
const FSRef *container,
ItemCount maxLevels,
FSCatalogInfoBitmap whichInfo,
Boolean wantFSSpec,
Boolean wantName,
IterateContainerFilterProcPtr iterateFilter,
void *yourDataPtr);
/*
The FSIterateContainer function performs a recursive iteration (scan) of the
specified container directory and calls your IterateContainerFilterProc
function once for each file and directory found.
The maxLevels parameter lets you control how deep the recursion goes.
If maxLevels is 1, FSIterateContainer only scans the specified directory;
if maxLevels is 2, FSIterateContainer scans the specified directory and
one subdirectory below the specified directory; etc. Set maxLevels to
zero to scan all levels.
The yourDataPtr parameter can point to whatever data structure you might
want to access from within your IterateContainerFilterProc.
container --> The FSRef to the container directory to iterate.
maxLevels --> Maximum number of directory levels to scan or
zero to scan all directory levels.
whichInfo --> The fields of the FSCatalogInfo you wish to get.
wantFSSpec --> Set to true if you want the FSSpec to each
object passed to your IterateContainerFilterProc.
wantName --> Set to true if you want the name of each
object passed to your IterateContainerFilterProc.
iterateFilter --> A pointer to the IterateContainerFilterProc you
want called once for each file and directory found
by FSIterateContainer.
yourDataPtr --> An optional pointer to whatever data structure you
might want to access from within the
IterateFilterProc.
*/
/*****************************************************************************/
#pragma mark FSGetDirectoryItems
OSErr
FSGetDirectoryItems(
const FSRef *container,
FSRef ***refsHandle, /* pointer to handle of FSRefs */
ItemCount *numRefs,
Boolean *containerChanged);
/*
The FSGetDirectoryItems function returns the list of items in the specified
container. The array of FSRef records is returned in a Handle, refsHandle,
which is allocated by FSGetDirectoryItems. The caller is responsible for
disposing of refsHandle if the FSGetDirectoryItems returns noErr.
container --> FSRef to a directory.
refsHandle <-- Pointer to an FSRef Handle where the array of
FSRefs is to be returned.
numRefs <-- The number of FSRefs returned in the array.
containerChanged <-- Set to true if the container changes while the
list of items is being obtained.
*/
/*****************************************************************************/
#pragma mark FSExchangeObjectsCompat
OSErr
FSExchangeObjectsCompat(
const FSRef *sourceRef,
const FSRef *destRef,
FSRef *newSourceRef,
FSRef *newDestRef);
/*
The FSExchangeObjectsCompat function exchanges the data between two files.
The FSExchangeObjectsCompat function is an enhanced version of
FSExchangeObjects function. The two enhancements FSExchangeObjectsCompat
provides are:
1, FSExchangeObjectsCompat will work on volumes which do not support
FSExchangeObjects. FSExchangeObjectsCompat does this by emulating
FSExchangeObjects through a series of File Manager operations. If
there is a failure at any step along the way, FSExchangeObjectsCompat
attempts to undo any steps already taken to leave the files in their
original state in their original locations.
2. FSExchangeObjectsCompat returns new FSRefs to the source and
destination files. Note that if this function fails at any step along
the way, newSourceRef and newDestRef still give you access to the final
locations of the files being exchanged -- even if they are renamed or
not in their original locations.
sourceRef --> FSRef to the source file.
destRef --> FSRef to the destination file.
newSourceRef <-- The new FSRef to the source file.
newDestRef <-- The new FSRef to the destination file.
*/
/*****************************************************************************/
#pragma mark ----- Shared Environment Routines -----
/*****************************************************************************/
#if 0
/* These methods were added in 10.4, and are not used by ResKnife, so we just comment them out to avoid errors */
#pragma mark FSLockRange
OSErr
FSLockRange(
SInt16 refNum,
SInt32 rangeLength,
SInt32 rangeStart);
/*
The LockRange function locks (denies access to) a portion of a file
that was opened with shared read/write permission.
refNum --> The file reference number of an open file.
rangeLength --> The number of bytes in the range.
rangeStart --> The starting byte in the range to lock.
__________
Also see: UnlockRange
*/
/*****************************************************************************/
#pragma mark FSUnlockRange
OSErr
FSUnlockRange(
SInt16 refNum,
SInt32 rangeLength,
SInt32 rangeStart);
/*
The UnlockRange function unlocks (allows access to) a previously locked
portion of a file that was opened with shared read/write permission.
refNum --> The file reference number of an open file.
rangeLength --> The number of bytes in the range.
rangeStart --> The starting byte in the range to unlock.
__________
Also see: LockRange
*/
#endif
/*****************************************************************************/
#pragma mark FSGetDirAccess
OSErr
FSGetDirAccess(
const FSRef *ref,
SInt32 *ownerID, /* can be NULL */
SInt32 *groupID, /* can be NULL */
SInt32 *accessRights); /* can be NULL */
/*
The FSGetDirAccess function retrieves the directory access control
information for a directory on a shared volume.
ref --> An FSRef specifying the directory.
ownerID <** An optional pointer to a SInt32.
If not NULL, the directory's owner ID
will be returned in the SInt32.
groupID <** An optional pointer to a SInt32.
If not NULL, the directory's group ID, or 0
if no group affiliation, will be returned in
the SInt32.
accessRights <** An optional pointer to a SInt32.
If not NULL, the directory's access rights
will be returned in the SInt32.
__________
Also see: FSSetDirAccess, FSMapID, FSMapName
*/
/*****************************************************************************/
#pragma mark FSSetDirAccess
OSErr
FSSetDirAccess(
const FSRef *ref,
SInt32 ownerID,
SInt32 groupID,
SInt32 accessRights);
/*
The FSpSetDirAccess function changes the directory access control
information for a directory on a shared volume. You must be the owner of
a directory to change its access control information.
ref --> An FSRef specifying the directory.
ownerID --> The directory's owner ID.
groupID --> The directory's group ID or 0 if no group affiliation.
accessRights --> The directory's access rights.
__________
Also see: FSGetDirAccess, FSMapID, FSMapName
*/
/*****************************************************************************/
#pragma mark FSGetVolMountInfoSize
OSErr
FSGetVolMountInfoSize(
FSVolumeRefNum volRefNum,
SInt16 *size);
/*
The FSGetVolMountInfoSize function determines the how much space the
program needs to allocate for a volume mounting information record.
volRefNum --> Volume specification.
size <-- The space needed (in bytes) of the volume
mounting information record.
__________
Also see: FSGetVolMountInfo, VolumeMount
*/
/*****************************************************************************/
#pragma mark FSGetVolMountInfo
OSErr
FSGetVolMountInfo(
FSVolumeRefNum volRefNum,
void *volMountInfo);
/*
The FSGetVolMountInfo function retrieves a volume mounting information
record containing all the information needed to mount the volume,
except for passwords.
volRefNum --> Volume specification.
volMountInfo <-- The volume mounting information.
__________
Also see: FSGetVolMountInfoSize, VolumeMount
*/
/*****************************************************************************/
#if 0
/* This method were added in 10.4, and are not used by ResKnife, so we just comment it out to avoid errors */
#pragma mark FSVolumeMount
OSErr
FSVolumeMount(
const void *volMountInfo,
FSVolumeRefNum *volRefNum);
/*
The VolumeMount function mounts a volume using a volume mounting
information record.
volMountInfo --> A volume mounting information record.
volRefNum <-- The volume reference number.
__________
Also see: FSGetVolMountInfoSize, FSGetVolMountInfo
*/
#endif
/*****************************************************************************/
#pragma mark FSMapID
OSErr
FSMapID(
FSVolumeRefNum volRefNum,
SInt32 ugID,
SInt16 objType,
Str31 name);
/*
The FSMapID function determines the name of a user or group if you know
the user or group ID.
volRefNum --> Volume specification.
objType --> The mapping function code:
kOwnerID2Name to map a user ID to a user name
kGroupID2Name to map a group ID to a group name
name <** An optional pointer to a buffer (minimum Str31).
If not NULL, the user or group name
will be returned in the buffer.
__________
Also see: FSGetDirAccess, FSSetDirAccess, FSMapName
*/
/*****************************************************************************/
#pragma mark FSMapName
OSErr
FSMapName(
FSVolumeRefNum volRefNum,
ConstStr255Param name,
SInt16 objType,
SInt32 *ugID);
/*
The FSMapName function determines the user or group ID if you know the
user or group name.
volRefNum --> Volume specification.
name --> The user or group name.
objType --> The mapping function code:
kOwnerName2ID to map a user name to a user ID
kGroupName2ID to map a user name to a group ID
ugID <-- The user or group ID.
__________
Also see: FSGetDirAccess, FSSetDirAccess, FSMapID
*/
/*****************************************************************************/
#pragma mark FSCopyFile
OSErr
FSCopyFile(
const FSRef *srcFileRef,
const FSRef *dstDirectoryRef,
UniCharCount nameLength,
const UniChar *copyName, /* can be NULL (no rename during copy) */
TextEncoding textEncodingHint,
FSRef *newRef); /* can be NULL */
/*
The FSCopyFile function duplicates a file and optionally renames it.
The source and destination volumes must be on the same file server.
This function instructs the server to copy the file.
srcFileRef --> An FSRef specifying the source file.
dstDirectoryRef --> An FSRef specifying the destination directory.
nameLength --> Number of UniChar in copyName parameter (ignored
if copyName is NULL).
copyName --> Points to the new file name if the file is to be
renamed, or NULL if the file isn't to be renamed.
textEncodingHint --> The text encoding hint used for the rename.
You can pass kTextEncodingUnknown to use the
"default" textEncodingHint.
newRef <** An optional pointer to a FSRef.
If not NULL, the FSRef of the duplicated file
will be returned in the FSRef.
*/
/*****************************************************************************/
#pragma mark FSMoveRename
OSErr
FSMoveRename(
const FSRef *srcFileRef,
const FSRef *dstDirectoryRef,
UniCharCount nameLength,
const UniChar *moveName, /* can be NULL (no rename during move) */
TextEncoding textEncodingHint,
FSRef *newRef); /* can be NULL */
/*
The FSMoveRename function moves a file or directory (object), and
optionally renames it. The source and destination locations must be on
the same shared volume.
srcFileRef --> An FSRef specifying the source file.
dstDirectoryRef --> An FSRef specifying the destination directory.
nameLength --> Number of UniChar in moveName parameter (ignored
if copyName is NULL)
moveName --> Points to the new object name if the object is to be
renamed, or NULL if the object isn't to be renamed.
textEncodingHint --> The text encoding hint used for the rename.
You can pass kTextEncodingUnknown to use the
"default" textEncodingHint.
newRef <** An optional pointer to a FSRef.
If not NULL, the FSRef of the moved object
will be returned in the FSRef.
*/
/*****************************************************************************/
#pragma mark ----- File ID Routines -----
/*****************************************************************************/
#pragma mark FSResolveFileIDRef
OSErr
FSResolveFileIDRef(
FSVolumeRefNum volRefNum,
SInt32 fileID,
FSRef *ref);
/*
The FSResolveFileIDRef function returns an FSRef for the file with the
specified file ID reference.
volRefNum --> Volume specification.
fileID --> The file ID reference.
ref <-- The FSRef for the file ID reference.
__________
Also see: FSCreateFileIDRef, FSDeleteFileIDRef
*/
/*****************************************************************************/
#pragma mark FSCreateFileIDRef
OSErr
FSCreateFileIDRef(
const FSRef *ref,
SInt32 *fileID);
/*
The FSCreateFileIDRef function creates a file ID reference for the
specified file, or if a file ID reference already exists, supplies
the file ID reference and returns the result code fidExists or afpIDExists.
ref --> The FSRef for the file.
fileID <-- The file ID reference (if result is noErr,
fidExists, or afpIDExists).
__________
Also see: GetFSRefFromFileIDRef, FSDeleteFileIDRef
*/
/*****************************************************************************/
#pragma mark FSDeleteFileIDRef
/*
Why is there no FSDeleteFileIDRef routine? There are two reasons:
1. Since Mac OS 8.1, PBDeleteFileIDRef hasn't deleted file ID references.
On HFS volumes, deleting a file ID reference breaks aliases (which
use file ID references to track files as they are moved around on a
volume) and file ID references are automatically deleted when the file
they refer to is deleted. On HFS Plus volumes, file ID references are
always created when a file is created, deleted when the file is deleted,
and cannot be deleted at any other time.
2. PBDeleteFileIDRef causes a memory access fault under Mac OS X 10.0
through 10.1.x. While this will be fixed in a future release, the
implementation, like the Mac OS 8/9 implementation, does not delete
file ID references.
__________
Also see: GetFSRefFromFileIDRef, FSCreateFileIDRef
*/
/*****************************************************************************/
#pragma mark ----- Utility Routines -----
/*****************************************************************************/
#pragma mark GetTempBuffer
Ptr
GetTempBuffer(
ByteCount buffReqSize,
ByteCount *buffActSize);
/*
The GetTempBuffer function allocates a temporary buffer for file system
operations which is at least 4K bytes and a multiple of 4K bytes.
buffReqSize --> Size you'd like the buffer to be.
buffActSize <-- The size of the buffer allocated.
function result <-- Pointer to memory allocated, or NULL if no memory
was available. The caller is responsible for
disposing of this buffer with DisposePtr.
*/
/*****************************************************************************/
#pragma mark FileRefNumGetFSRef
OSErr
FileRefNumGetFSRef(
short refNum,
FSRef *ref);
/*
The FileRefNumGetFSRef function gets the FSRef of an open file.
refNum --> The file reference number of an open file.
ref <-- The FSRef to the open file.
*/
/*****************************************************************************/
#pragma mark FSSetDefault
OSErr
FSSetDefault(
const FSRef *newDefault,
FSRef *oldDefault);
/*
The FSSetDefault function sets the current working directory to the
directory specified by newDefault. The previous current working directory
is returned in oldDefault and must be used to restore the current working
directory to its previous state with the FSRestoreDefault function.
These two functions are designed to be used as a wrapper around
Standard I/O routines where the location of the file is implied to be the
current working directory. This is how you should use these functions:
result = FSSetDefault(&newDefault, &oldDefault);
if ( noErr == result )
{
// call the Stdio functions like remove, rename,
// fopen, freopen, etc here!
result = FSRestoreDefault(&oldDefault);
}
newDefault --> An FSRef that specifies the new current working
directory.
oldDefault <-- The previous current working directory's FSRef.
__________
Also see: FSRestoreDefault
*/
/*****************************************************************************/
#pragma mark FSRestoreDefault
OSErr
FSRestoreDefault(
const FSRef *oldDefault);
/*
The FSRestoreDefault function restores the current working directory
to the directory specified by oldDefault. The oldDefault parameter was
previously obtained from the FSSetDefault function.
These two functions are designed to be used as a wrapper around
Standard I/O routines where the location of the file is implied to be the
current working directory. This is how you should use these functions:
result = FSSetDefault(&newDefault, &oldDefault);
if ( noErr == result )
{
// call the Stdio functions like remove, rename,
// fopen, freopen, etc here!
result = FSRestoreDefault(&oldDefault);
}
oldDefault --> The FSRef of the location to restore.
__________
Also see: FSSetDefault
*/
/*****************************************************************************/
#if PRAGMA_STRUCT_ALIGN
#pragma options align=reset
#elif PRAGMA_STRUCT_PACKPUSH
#pragma pack(pop)
#elif PRAGMA_STRUCT_PACK
#pragma pack()
#endif
#ifdef PRAGMA_IMPORT_OFF
#pragma import off
#elif PRAGMA_IMPORT
#pragma import reset
#endif
#ifdef __cplusplus
}
#endif
#endif /* __MOREFILESX__ */
\ No newline at end of file
diff --git a/HexEditor.graffle b/HexEditor.graffle
index 7b59199..6a0e07c 100644
--- a/HexEditor.graffle
+++ b/HexEditor.graffle
@@ -4,8 +4,10 @@
CanvasColor
+ a
+ 1w
- 1.000000e+00
+ 1ColumnAlign0
@@ -21,10 +23,10 @@
HeadID
- 31
+ 27ID
- 33
+ 29Points{319.5, 504}
@@ -45,7 +47,7 @@
TailID
- 26
+ 22
@@ -54,10 +56,10 @@
HeadID
- 31
+ 27ID
- 32
+ 28Points{276.3, 504}
@@ -78,7 +80,7 @@
TailID
- 25
+ 21
@@ -87,10 +89,10 @@
HeadID
- 22
+ 18ID
- 31
+ 27Points{279, 558}
@@ -116,10 +118,10 @@
HeadID
- 31
+ 27ID
- 30
+ 26Points{233.1, 504}
@@ -140,7 +142,7 @@
TailID
- 24
+ 20
@@ -149,10 +151,10 @@
HeadID
- 11
+ 7ID
- 29
+ 25Points{321.577, 432}
@@ -173,7 +175,7 @@
TailID
- 26
+ 22
@@ -182,10 +184,10 @@
HeadID
- 11
+ 7ID
- 28
+ 24Points{271.731, 432}
@@ -206,7 +208,7 @@
TailID
- 25
+ 21
@@ -215,10 +217,10 @@
HeadID
- 24
+ 20ID
- 27
+ 23Points{250.962, 378}
@@ -239,7 +241,7 @@
TailID
- 11
+ 7
@@ -248,7 +250,7 @@
ClassShapedGraphicID
- 26
+ 22ShapeHorizontalBracketsText
@@ -259,7 +261,8 @@
{\colortbl;\red255\green255\blue255;}
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
-\f0\fs24 \cf0 Hex Text View (ASCII)}
+\f0\fs24 \cf0 ASCII\
+Text View}
@@ -268,7 +271,7 @@
ClassShapedGraphicID
- 25
+ 21ShapeHorizontalBracketsText
@@ -279,7 +282,8 @@
{\colortbl;\red255\green255\blue255;}
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
-\f0\fs24 \cf0 Hex Text View (Hex)}
+\f0\fs24 \cf0 Hex\
+Text View}
@@ -288,7 +292,7 @@
ClassShapedGraphicID
- 24
+ 20ShapeHorizontalBracketsText
@@ -299,7 +303,8 @@
{\colortbl;\red255\green255\blue255;}
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
-\f0\fs24 \cf0 Hex Text View (Offset)}
+\f0\fs24 \cf0 Offset\
+Text View}
@@ -308,10 +313,10 @@
HeadID
- 22
+ 18ID
- 23
+ 19Points{297.807, 236.054}
@@ -332,7 +337,7 @@
TailID
- 9
+ 5
@@ -341,7 +346,7 @@
ClassShapedGraphicID
- 22
+ 18ShapeCloudStyle
@@ -350,12 +355,14 @@
Color
+ a
+ 1b
- 1.000000e+00
+ 1g
- 8.490366e-01
+ 0.849037r
- 9.965038e-01
+ 0.996504
@@ -376,14 +383,14 @@
HeadID
- 11
+ 7ID
- 21
+ 17Points
- {144, 348.527}
- {207, 349.809}
+ {144, 347.879}
+ {207, 349.497}Style
@@ -400,7 +407,7 @@
TailID
- 17
+ 13
@@ -409,14 +416,14 @@
HeadID
- 17
+ 13ID
- 20
+ 16Points
- {100.788, 239.348}
- {99.8262, 297}
+ {100.786, 239.348}
+ {99.8251, 297}Style
@@ -433,7 +440,7 @@
TailID
- 18
+ 14
@@ -442,10 +449,10 @@
HeadID
- 18
+ 14ID
- 19
+ 15Points{218.607, 211.5}
@@ -466,7 +473,7 @@
TailID
- 9
+ 5
@@ -475,7 +482,7 @@
ClassShapedGraphicID
- 18
+ 14ShapeCloudStyle
@@ -484,12 +491,14 @@
Color
+ a
+ 1b
- 1.000000e+00
+ 1g
- 9.653430e-01
+ 0.965343r
- 7.682484e-01
+ 0.768248
@@ -515,7 +524,7 @@
ClassShapedGraphicID
- 16
+ 12ShapeRoundRectStyle
@@ -524,12 +533,14 @@
Color
+ a
+ 1b
- 1.000000e+00
+ 1g
- 7.482798e-01
+ 0.74828r
- 4.663317e-01
+ 0.466332shadow
@@ -537,13 +548,13 @@
Colora
- 5.000000e-01
+ 0.5b
- 7.500000e-01
+ 0.75g
- 7.500000e-01
+ 0.75r
- 7.500000e-01
+ 0.75stroke
@@ -559,7 +570,7 @@
ClassShapedGraphicID
- 17
+ 13ShapeRectangleText
@@ -576,7 +587,7 @@ Sheet}
ID
- 15
+ 11Class
@@ -584,14 +595,14 @@ Sheet}
HeadID
- 12
+ 8ID
- 14
+ 10Points
- {267.14, 239.328}
- {265.695, 306}
+ {267.145, 239.33}
+ {265.696, 306}Style
@@ -608,7 +619,7 @@ Sheet}
TailID
- 9
+ 5
@@ -617,14 +628,14 @@ Sheet}
HeadID
- 9
+ 5ID
- 13
+ 9Points{266.062, 117}
- {267.252, 183.589}
+ {267.252, 183.588}Style
@@ -641,7 +652,7 @@ Sheet}
TailID
- 7
+ 3
@@ -655,7 +666,7 @@ Sheet}
ClassShapedGraphicID
- 11
+ 7ShapeRectangle
@@ -665,7 +676,7 @@ Sheet}
ClassShapedGraphicID
- 12
+ 8ShapeRectangleText
@@ -681,7 +692,7 @@ Sheet}
ID
- 10
+ 6Bounds
@@ -689,7 +700,7 @@ Sheet}
ClassShapedGraphicID
- 9
+ 5ShapeCloudStyle
@@ -698,12 +709,14 @@ Sheet}
Color
+ a
+ 1b
- 1.000000e+00
+ 1g
- 9.653430e-01
+ 0.965343r
- 7.682484e-01
+ 0.768248
@@ -729,7 +742,7 @@ Sheet}
ClassShapedGraphicID
- 6
+ 2Magnets{0, 1}
@@ -756,7 +769,7 @@ Sheet}
ClassShapedGraphicID
- 7
+ 3ShapeRectangleStyle
@@ -765,12 +778,14 @@ Sheet}
Color
+ a
+ 1b
- 0.000000e+00
+ 0g
- 0.000000e+00
+ 0r
- 0.000000e+00
+ 0Width2.000000e+00
@@ -783,7 +798,7 @@ Sheet}
ClassShapedGraphicID
- 8
+ 4ShapeRectangleStyle
@@ -793,21 +808,23 @@ Sheet}
Colora
- 5.000000e-01
+ 0.5w
- 3.333334e-01
+ 0.333333strokeColor
+ a
+ 1b
- 0.000000e+00
+ 0g
- 0.000000e+00
+ 0r
- 0.000000e+00
+ 0Width2.000000e+00
@@ -826,7 +843,7 @@ Sheet}
ID
- 5
+ 1GridInfo
@@ -864,8 +881,10 @@ Sheet}
YESPageBreakColor
+ a
+ 1w
- 6.666667e-01
+ 0.666667PageBreaksYES
@@ -873,178 +892,178 @@ Sheet}
BAt0eXBlZHN0cmVhbYED6IQBQISEhAtOU1ByaW50SW5mbwGEhAhOU09iamVjdACFkoSE
hBNOU011dGFibGVEaWN0aW9uYXJ5AISEDE5TRGljdGlvbmFyeQCUhAFpF5KEhIQITlNT
- dHJpbmcBlIQBKw9OU1BhZ2VzUGVyU2hlZXSGkoSEhAhOU051bWJlcgCEhAdOU1ZhbHVl
- AJSEASqEhAFznQGGkoSZmQ5OU0JvdHRvbU1hcmdpboaShJuchIQBZp4khpKEmZkPTlNQ
- cmludEFsbFBhZ2VzhpKEm5ydnQCGkoSZmQ1OU0pvYkZlYXR1cmVzhpKElpcAhpKEmZkV
- TlNIb3Jpem9uYWxQYWdpbmF0aW9uhpKEm5ydnQCGkoSZmRROU1ZlcnRpY2FsbHlDZW50
- ZXJlZIaShJucnZ0BhpKEmZkJTlNQcmludGVyhpKEhIQJTlNQcmludGVyAJSShJmZASCG
- hpKEmZkPTlNTY2FsaW5nRmFjdG9yhpKEm5ygngGGkoSZmRJOU1JldmVyc2VQYWdlT3Jk
- ZXKGkqKShJmZDE5TTGVmdE1hcmdpboaShJucoJ4khpKEmZkOTlNQTVBhZ2VGb3JtYXSG
- koSEhAZOU0RhdGEAlJeBHyCEB1s3OTY4Y108P3htbCB2ZXJzaW9uPSIxLjAiIGVuY29k
- aW5nPSJVVEYtOCI/Pgo8IURPQ1RZUEUgcGxpc3QgUFVCTElDICItLy9BcHBsZSBDb21w
- dXRlci8vRFREIFBMSVNUIDEuMC8vRU4iICJodHRwOi8vd3d3LmFwcGxlLmNvbS9EVERz
- L1Byb3BlcnR5TGlzdC0xLjAuZHRkIj4KPHBsaXN0IHZlcnNpb249IjEuMCI+CjxkaWN0
- PgoJPGtleT5jb20uYXBwbGUucHJpbnQuUGFnZUZvcm1hdC5QTUhvcml6b250YWxSZXM8
- L2tleT4KCTxkaWN0PgoJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5jcmVhdG9y
- PC9rZXk+CgkJPHN0cmluZz5jb20uYXBwbGUucHJpbnRpbmdtYW5hZ2VyPC9zdHJpbmc+
- CgkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0Lml0ZW1BcnJheTwva2V5PgoJCTxh
- cnJheT4KCQkJPGRpY3Q+CgkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC5QYWdlRm9ybWF0
- LlBNSG9yaXpvbnRhbFJlczwva2V5PgoJCQkJPHJlYWw+Ny4yMDAwMDAwMDAwMDAwMDBl
- KzAxPC9yZWFsPgoJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNsaWVudDwv
- a2V5PgoJCQkJPHN0cmluZz5jb20uYXBwbGUucHJpbnRpbmdtYW5hZ2VyPC9zdHJpbmc+
- CgkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQubW9kRGF0ZTwva2V5PgoJCQkJ
- PGRhdGU+MjAwMi0xMS0xN1QwMDoxNjowOVo8L2RhdGU+CgkJCQk8a2V5PmNvbS5hcHBs
- ZS5wcmludC50aWNrZXQuc3RhdGVGbGFnPC9rZXk+CgkJCQk8aW50ZWdlcj4wPC9pbnRl
- Z2VyPgoJCQk8L2RpY3Q+CgkJPC9hcnJheT4KCTwvZGljdD4KCTxrZXk+Y29tLmFwcGxl
- LnByaW50LlBhZ2VGb3JtYXQuUE1PcmllbnRhdGlvbjwva2V5PgoJPGRpY3Q+CgkJPGtl
- eT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNyZWF0b3I8L2tleT4KCQk8c3RyaW5nPmNv
- bS5hcHBsZS5wcmludGluZ21hbmFnZXI8L3N0cmluZz4KCQk8a2V5PmNvbS5hcHBsZS5w
- cmludC50aWNrZXQuaXRlbUFycmF5PC9rZXk+CgkJPGFycmF5PgoJCQk8ZGljdD4KCQkJ
- CTxrZXk+Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQuUE1PcmllbnRhdGlvbjwva2V5
- PgoJCQkJPGludGVnZXI+MTwvaW50ZWdlcj4KCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50
- LnRpY2tldC5jbGllbnQ8L2tleT4KCQkJCTxzdHJpbmc+Y29tLmFwcGxlLnByaW50aW5n
- bWFuYWdlcjwvc3RyaW5nPgoJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0Lm1v
- ZERhdGU8L2tleT4KCQkJCTxkYXRlPjIwMDItMTEtMTdUMDA6MTY6MDlaPC9kYXRlPgoJ
- CQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LnN0YXRlRmxhZzwva2V5PgoJCQkJ
- PGludGVnZXI+MDwvaW50ZWdlcj4KCQkJPC9kaWN0PgoJCTwvYXJyYXk+Cgk8L2RpY3Q+
- Cgk8a2V5PmNvbS5hcHBsZS5wcmludC5QYWdlRm9ybWF0LlBNU2NhbGluZzwva2V5PgoJ
- PGRpY3Q+CgkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNyZWF0b3I8L2tleT4K
- CQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21hbmFnZXI8L3N0cmluZz4KCQk8a2V5
- PmNvbS5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycmF5PC9rZXk+CgkJPGFycmF5PgoJ
- CQk8ZGljdD4KCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQuUE1TY2Fs
- aW5nPC9rZXk+CgkJCQk8cmVhbD4xLjAwMDAwMDAwMDAwMDAwMGUrMDA8L3JlYWw+CgkJ
- CQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuY2xpZW50PC9rZXk+CgkJCQk8c3Ry
- aW5nPmNvbS5hcHBsZS5wcmludGluZ21hbmFnZXI8L3N0cmluZz4KCQkJCTxrZXk+Y29t
- LmFwcGxlLnByaW50LnRpY2tldC5tb2REYXRlPC9rZXk+CgkJCQk8ZGF0ZT4yMDAyLTEx
- LTE3VDAwOjE2OjA5WjwvZGF0ZT4KCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tl
- dC5zdGF0ZUZsYWc8L2tleT4KCQkJCTxpbnRlZ2VyPjA8L2ludGVnZXI+CgkJCTwvZGlj
- dD4KCQk8L2FycmF5PgoJPC9kaWN0PgoJPGtleT5jb20uYXBwbGUucHJpbnQuUGFnZUZv
- cm1hdC5QTVZlcnRpY2FsUmVzPC9rZXk+Cgk8ZGljdD4KCQk8a2V5PmNvbS5hcHBsZS5w
- cmludC50aWNrZXQuY3JlYXRvcjwva2V5PgoJCTxzdHJpbmc+Y29tLmFwcGxlLnByaW50
- aW5nbWFuYWdlcjwvc3RyaW5nPgoJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5p
- dGVtQXJyYXk8L2tleT4KCQk8YXJyYXk+CgkJCTxkaWN0PgoJCQkJPGtleT5jb20uYXBw
- bGUucHJpbnQuUGFnZUZvcm1hdC5QTVZlcnRpY2FsUmVzPC9rZXk+CgkJCQk8cmVhbD43
- LjIwMDAwMDAwMDAwMDAwMGUrMDE8L3JlYWw+CgkJCQk8a2V5PmNvbS5hcHBsZS5wcmlu
- dC50aWNrZXQuY2xpZW50PC9rZXk+CgkJCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGlu
- Z21hbmFnZXI8L3N0cmluZz4KCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5t
- b2REYXRlPC9rZXk+CgkJCQk8ZGF0ZT4yMDAyLTExLTE3VDAwOjE2OjA5WjwvZGF0ZT4K
- CQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5zdGF0ZUZsYWc8L2tleT4KCQkJ
- CTxpbnRlZ2VyPjA8L2ludGVnZXI+CgkJCTwvZGljdD4KCQk8L2FycmF5PgoJPC9kaWN0
- PgoJPGtleT5jb20uYXBwbGUucHJpbnQuUGFnZUZvcm1hdC5QTVZlcnRpY2FsU2NhbGlu
- Zzwva2V5PgoJPGRpY3Q+CgkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNyZWF0
- b3I8L2tleT4KCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21hbmFnZXI8L3N0cmlu
- Zz4KCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycmF5PC9rZXk+CgkJ
- PGFycmF5PgoJCQk8ZGljdD4KCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LlBhZ2VGb3Jt
- YXQuUE1WZXJ0aWNhbFNjYWxpbmc8L2tleT4KCQkJCTxyZWFsPjEuMDAwMDAwMDAwMDAw
- MDAwZSswMDwvcmVhbD4KCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5jbGll
- bnQ8L2tleT4KCQkJCTxzdHJpbmc+Y29tLmFwcGxlLnByaW50aW5nbWFuYWdlcjwvc3Ry
- aW5nPgoJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0Lm1vZERhdGU8L2tleT4K
- CQkJCTxkYXRlPjIwMDItMTEtMTdUMDA6MTY6MDlaPC9kYXRlPgoJCQkJPGtleT5jb20u
- YXBwbGUucHJpbnQudGlja2V0LnN0YXRlRmxhZzwva2V5PgoJCQkJPGludGVnZXI+MDwv
- aW50ZWdlcj4KCQkJPC9kaWN0PgoJCTwvYXJyYXk+Cgk8L2RpY3Q+Cgk8a2V5PmNvbS5h
- cHBsZS5wcmludC5zdWJUaWNrZXQucGFwZXJfaW5mb190aWNrZXQ8L2tleT4KCTxkaWN0
- PgoJCTxrZXk+Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQuUE1BZGp1c3RlZFBhZ2VS
- ZWN0PC9rZXk+CgkJPGRpY3Q+CgkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5j
- cmVhdG9yPC9rZXk+CgkJCTxzdHJpbmc+Y29tLmFwcGxlLnByaW50aW5nbWFuYWdlcjwv
- c3RyaW5nPgoJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycmF5PC9r
- ZXk+CgkJCTxhcnJheT4KCQkJCTxkaWN0PgoJCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50
- LlBhZ2VGb3JtYXQuUE1BZGp1c3RlZFBhZ2VSZWN0PC9rZXk+CgkJCQkJPGFycmF5PgoJ
- CQkJCQk8cmVhbD4wLjAwMDAwMDAwMDAwMDAwMGUrMDA8L3JlYWw+CgkJCQkJCTxyZWFs
- PjAuMDAwMDAwMDAwMDAwMDAwZSswMDwvcmVhbD4KCQkJCQkJPHJlYWw+Ny44MzAwMDAw
- MDAwMDAwMDBlKzAyPC9yZWFsPgoJCQkJCQk8cmVhbD41LjU5MDAwMDAwMDAwMDAwMGUr
- MDI8L3JlYWw+CgkJCQkJPC9hcnJheT4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50
- aWNrZXQuY2xpZW50PC9rZXk+CgkJCQkJPHN0cmluZz5jb20uYXBwbGUucHJpbnRpbmdt
- YW5hZ2VyPC9zdHJpbmc+CgkJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0Lm1v
- ZERhdGU8L2tleT4KCQkJCQk8ZGF0ZT4yMDAyLTExLTE3VDAwOjE2OjA5WjwvZGF0ZT4K
- CQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuc3RhdGVGbGFnPC9rZXk+CgkJ
- CQkJPGludGVnZXI+MDwvaW50ZWdlcj4KCQkJCTwvZGljdD4KCQkJPC9hcnJheT4KCQk8
- L2RpY3Q+CgkJPGtleT5jb20uYXBwbGUucHJpbnQuUGFnZUZvcm1hdC5QTUFkanVzdGVk
- UGFwZXJSZWN0PC9rZXk+CgkJPGRpY3Q+CgkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRp
- Y2tldC5jcmVhdG9yPC9rZXk+CgkJCTxzdHJpbmc+Y29tLmFwcGxlLnByaW50aW5nbWFu
- YWdlcjwvc3RyaW5nPgoJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFy
- cmF5PC9rZXk+CgkJCTxhcnJheT4KCQkJCTxkaWN0PgoJCQkJCTxrZXk+Y29tLmFwcGxl
- LnByaW50LlBhZ2VGb3JtYXQuUE1BZGp1c3RlZFBhcGVyUmVjdDwva2V5PgoJCQkJCTxh
- cnJheT4KCQkJCQkJPHJlYWw+LTEuODAwMDAwMDAwMDAwMDAwZSswMTwvcmVhbD4KCQkJ
- CQkJPHJlYWw+LTEuODAwMDAwMDAwMDAwMDAwZSswMTwvcmVhbD4KCQkJCQkJPHJlYWw+
- OC4yNDAwMDAwMDAwMDAwMDBlKzAyPC9yZWFsPgoJCQkJCQk8cmVhbD41Ljc3MDAwMDAw
- MDAwMDAwMGUrMDI8L3JlYWw+CgkJCQkJPC9hcnJheT4KCQkJCQk8a2V5PmNvbS5hcHBs
- ZS5wcmludC50aWNrZXQuY2xpZW50PC9rZXk+CgkJCQkJPHN0cmluZz5jb20uYXBwbGUu
- cHJpbnRpbmdtYW5hZ2VyPC9zdHJpbmc+CgkJCQkJPGtleT5jb20uYXBwbGUucHJpbnQu
- dGlja2V0Lm1vZERhdGU8L2tleT4KCQkJCQk8ZGF0ZT4yMDAyLTExLTE3VDAwOjE2OjA5
- WjwvZGF0ZT4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuc3RhdGVGbGFn
- PC9rZXk+CgkJCQkJPGludGVnZXI+MDwvaW50ZWdlcj4KCQkJCTwvZGljdD4KCQkJPC9h
- cnJheT4KCQk8L2RpY3Q+CgkJPGtleT5jb20uYXBwbGUucHJpbnQuUGFwZXJJbmZvLlBN
- UGFwZXJOYW1lPC9rZXk+CgkJPGRpY3Q+CgkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRp
- Y2tldC5jcmVhdG9yPC9rZXk+CgkJCTxzdHJpbmc+Y29tLmFwcGxlLnByaW50LnBtLlBv
- c3RTY3JpcHQ8L3N0cmluZz4KCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0Lml0
- ZW1BcnJheTwva2V5PgoJCQk8YXJyYXk+CgkJCQk8ZGljdD4KCQkJCQk8a2V5PmNvbS5h
- cHBsZS5wcmludC5QYXBlckluZm8uUE1QYXBlck5hbWU8L2tleT4KCQkJCQk8c3RyaW5n
- Pmlzby1hNDwvc3RyaW5nPgoJCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5j
- bGllbnQ8L2tleT4KCQkJCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludC5wbS5Qb3N0U2Ny
- aXB0PC9zdHJpbmc+CgkJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0Lm1vZERh
- dGU8L2tleT4KCQkJCQk8ZGF0ZT4yMDAwLTA3LTI4VDIyOjU3OjA0WjwvZGF0ZT4KCQkJ
+ dHJpbmcBlIQBKxBOU0pvYkRpc3Bvc2l0aW9uhpKEmZkPTlNQcmludFNwb29sSm9ihpKE
+ mZkZTlNQcmludFJldmVyc2VPcmllbnRhdGlvboaShISECE5TTnVtYmVyAISEB05TVmFs
+ dWUAlIQBKoSEAXOdAIaShJmZC05TUGFwZXJTaXplhpKEnpyEhAx7X05TU2l6ZT1mZn2e
+ gQJTgQNKhpKEmZkUTlNWZXJ0aWNhbFBhZ2luYXRpb26GkoSdnJ+dAIaShJmZFE5TVmVy
+ dGljYWxseUNlbnRlcmVkhpKEnZyfnQGGkoSZmRJOU1JldmVyc2VQYWdlT3JkZXKGkpyS
+ hJmZD05TUGFnZXNQZXJTaGVldIaShJ2cn50BhpKEmZkOTlNQTVBhZ2VGb3JtYXSGkoSE
+ hAZOU0RhdGEAlJeBHyCEB1s3OTY4Y108P3htbCB2ZXJzaW9uPSIxLjAiIGVuY29kaW5n
+ PSJVVEYtOCI/Pgo8IURPQ1RZUEUgcGxpc3QgUFVCTElDICItLy9BcHBsZSBDb21wdXRl
+ ci8vRFREIFBMSVNUIDEuMC8vRU4iICJodHRwOi8vd3d3LmFwcGxlLmNvbS9EVERzL1By
+ b3BlcnR5TGlzdC0xLjAuZHRkIj4KPHBsaXN0IHZlcnNpb249IjEuMCI+CjxkaWN0PgoJ
+ PGtleT5jb20uYXBwbGUucHJpbnQuUGFnZUZvcm1hdC5QTUhvcml6b250YWxSZXM8L2tl
+ eT4KCTxkaWN0PgoJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5jcmVhdG9yPC9r
+ ZXk+CgkJPHN0cmluZz5jb20uYXBwbGUucHJpbnRpbmdtYW5hZ2VyPC9zdHJpbmc+CgkJ
+ PGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0Lml0ZW1BcnJheTwva2V5PgoJCTxhcnJh
+ eT4KCQkJPGRpY3Q+CgkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC5QYWdlRm9ybWF0LlBN
+ SG9yaXpvbnRhbFJlczwva2V5PgoJCQkJPHJlYWw+Ny4yMDAwMDAwMDAwMDAwMDBlKzAx
+ PC9yZWFsPgoJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNsaWVudDwva2V5
+ PgoJCQkJPHN0cmluZz5jb20uYXBwbGUucHJpbnRpbmdtYW5hZ2VyPC9zdHJpbmc+CgkJ
+ CQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQubW9kRGF0ZTwva2V5PgoJCQkJPGRh
+ dGU+MjAwMi0xMS0xN1QwMDoxNjowOVo8L2RhdGU+CgkJCQk8a2V5PmNvbS5hcHBsZS5w
+ cmludC50aWNrZXQuc3RhdGVGbGFnPC9rZXk+CgkJCQk8aW50ZWdlcj4wPC9pbnRlZ2Vy
+ PgoJCQk8L2RpY3Q+CgkJPC9hcnJheT4KCTwvZGljdD4KCTxrZXk+Y29tLmFwcGxlLnBy
+ aW50LlBhZ2VGb3JtYXQuUE1PcmllbnRhdGlvbjwva2V5PgoJPGRpY3Q+CgkJPGtleT5j
+ b20uYXBwbGUucHJpbnQudGlja2V0LmNyZWF0b3I8L2tleT4KCQk8c3RyaW5nPmNvbS5h
+ cHBsZS5wcmludGluZ21hbmFnZXI8L3N0cmluZz4KCQk8a2V5PmNvbS5hcHBsZS5wcmlu
+ dC50aWNrZXQuaXRlbUFycmF5PC9rZXk+CgkJPGFycmF5PgoJCQk8ZGljdD4KCQkJCTxr
+ ZXk+Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQuUE1PcmllbnRhdGlvbjwva2V5PgoJ
+ CQkJPGludGVnZXI+MTwvaW50ZWdlcj4KCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRp
+ Y2tldC5jbGllbnQ8L2tleT4KCQkJCTxzdHJpbmc+Y29tLmFwcGxlLnByaW50aW5nbWFu
+ YWdlcjwvc3RyaW5nPgoJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0Lm1vZERh
+ dGU8L2tleT4KCQkJCTxkYXRlPjIwMDItMTEtMTdUMDA6MTY6MDlaPC9kYXRlPgoJCQkJ
+ PGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LnN0YXRlRmxhZzwva2V5PgoJCQkJPGlu
+ dGVnZXI+MDwvaW50ZWdlcj4KCQkJPC9kaWN0PgoJCTwvYXJyYXk+Cgk8L2RpY3Q+Cgk8
+ a2V5PmNvbS5hcHBsZS5wcmludC5QYWdlRm9ybWF0LlBNU2NhbGluZzwva2V5PgoJPGRp
+ Y3Q+CgkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNyZWF0b3I8L2tleT4KCQk8
+ c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21hbmFnZXI8L3N0cmluZz4KCQk8a2V5PmNv
+ bS5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycmF5PC9rZXk+CgkJPGFycmF5PgoJCQk8
+ ZGljdD4KCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQuUE1TY2FsaW5n
+ PC9rZXk+CgkJCQk8cmVhbD4xLjAwMDAwMDAwMDAwMDAwMGUrMDA8L3JlYWw+CgkJCQk8
+ a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuY2xpZW50PC9rZXk+CgkJCQk8c3RyaW5n
+ PmNvbS5hcHBsZS5wcmludGluZ21hbmFnZXI8L3N0cmluZz4KCQkJCTxrZXk+Y29tLmFw
+ cGxlLnByaW50LnRpY2tldC5tb2REYXRlPC9rZXk+CgkJCQk8ZGF0ZT4yMDAyLTExLTE3
+ VDAwOjE2OjA5WjwvZGF0ZT4KCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5z
+ dGF0ZUZsYWc8L2tleT4KCQkJCTxpbnRlZ2VyPjA8L2ludGVnZXI+CgkJCTwvZGljdD4K
+ CQk8L2FycmF5PgoJPC9kaWN0PgoJPGtleT5jb20uYXBwbGUucHJpbnQuUGFnZUZvcm1h
+ dC5QTVZlcnRpY2FsUmVzPC9rZXk+Cgk8ZGljdD4KCQk8a2V5PmNvbS5hcHBsZS5wcmlu
+ dC50aWNrZXQuY3JlYXRvcjwva2V5PgoJCTxzdHJpbmc+Y29tLmFwcGxlLnByaW50aW5n
+ bWFuYWdlcjwvc3RyaW5nPgoJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5pdGVt
+ QXJyYXk8L2tleT4KCQk8YXJyYXk+CgkJCTxkaWN0PgoJCQkJPGtleT5jb20uYXBwbGUu
+ cHJpbnQuUGFnZUZvcm1hdC5QTVZlcnRpY2FsUmVzPC9rZXk+CgkJCQk8cmVhbD43LjIw
+ MDAwMDAwMDAwMDAwMGUrMDE8L3JlYWw+CgkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50
+ aWNrZXQuY2xpZW50PC9rZXk+CgkJCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21h
+ bmFnZXI8L3N0cmluZz4KCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5tb2RE
+ YXRlPC9rZXk+CgkJCQk8ZGF0ZT4yMDAyLTExLTE3VDAwOjE2OjA5WjwvZGF0ZT4KCQkJ
+ CTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5zdGF0ZUZsYWc8L2tleT4KCQkJCTxp
+ bnRlZ2VyPjA8L2ludGVnZXI+CgkJCTwvZGljdD4KCQk8L2FycmF5PgoJPC9kaWN0PgoJ
+ PGtleT5jb20uYXBwbGUucHJpbnQuUGFnZUZvcm1hdC5QTVZlcnRpY2FsU2NhbGluZzwv
+ a2V5PgoJPGRpY3Q+CgkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNyZWF0b3I8
+ L2tleT4KCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21hbmFnZXI8L3N0cmluZz4K
+ CQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycmF5PC9rZXk+CgkJPGFy
+ cmF5PgoJCQk8ZGljdD4KCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQu
+ UE1WZXJ0aWNhbFNjYWxpbmc8L2tleT4KCQkJCTxyZWFsPjEuMDAwMDAwMDAwMDAwMDAw
+ ZSswMDwvcmVhbD4KCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5jbGllbnQ8
+ L2tleT4KCQkJCTxzdHJpbmc+Y29tLmFwcGxlLnByaW50aW5nbWFuYWdlcjwvc3RyaW5n
+ PgoJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0Lm1vZERhdGU8L2tleT4KCQkJ
+ CTxkYXRlPjIwMDItMTEtMTdUMDA6MTY6MDlaPC9kYXRlPgoJCQkJPGtleT5jb20uYXBw
+ bGUucHJpbnQudGlja2V0LnN0YXRlRmxhZzwva2V5PgoJCQkJPGludGVnZXI+MDwvaW50
+ ZWdlcj4KCQkJPC9kaWN0PgoJCTwvYXJyYXk+Cgk8L2RpY3Q+Cgk8a2V5PmNvbS5hcHBs
+ ZS5wcmludC5zdWJUaWNrZXQucGFwZXJfaW5mb190aWNrZXQ8L2tleT4KCTxkaWN0PgoJ
+ CTxrZXk+Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQuUE1BZGp1c3RlZFBhZ2VSZWN0
+ PC9rZXk+CgkJPGRpY3Q+CgkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5jcmVh
+ dG9yPC9rZXk+CgkJCTxzdHJpbmc+Y29tLmFwcGxlLnByaW50aW5nbWFuYWdlcjwvc3Ry
+ aW5nPgoJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycmF5PC9rZXk+
+ CgkJCTxhcnJheT4KCQkJCTxkaWN0PgoJCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LlBh
+ Z2VGb3JtYXQuUE1BZGp1c3RlZFBhZ2VSZWN0PC9rZXk+CgkJCQkJPGFycmF5PgoJCQkJ
+ CQk8cmVhbD4wLjAwMDAwMDAwMDAwMDAwMGUrMDA8L3JlYWw+CgkJCQkJCTxyZWFsPjAu
+ MDAwMDAwMDAwMDAwMDAwZSswMDwvcmVhbD4KCQkJCQkJPHJlYWw+Ny44MzAwMDAwMDAw
+ MDAwMDBlKzAyPC9yZWFsPgoJCQkJCQk8cmVhbD41LjU5MDAwMDAwMDAwMDAwMGUrMDI8
+ L3JlYWw+CgkJCQkJPC9hcnJheT4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNr
+ ZXQuY2xpZW50PC9rZXk+CgkJCQkJPHN0cmluZz5jb20uYXBwbGUucHJpbnRpbmdtYW5h
+ Z2VyPC9zdHJpbmc+CgkJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0Lm1vZERh
+ dGU8L2tleT4KCQkJCQk8ZGF0ZT4yMDAzLTExLTEwVDIxOjI4OjIyWjwvZGF0ZT4KCQkJ
CQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuc3RhdGVGbGFnPC9rZXk+CgkJCQkJ
- PGludGVnZXI+MTwvaW50ZWdlcj4KCQkJCTwvZGljdD4KCQkJPC9hcnJheT4KCQk8L2Rp
- Y3Q+CgkJPGtleT5jb20uYXBwbGUucHJpbnQuUGFwZXJJbmZvLlBNVW5hZGp1c3RlZFBh
- Z2VSZWN0PC9rZXk+CgkJPGRpY3Q+CgkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tl
+ PGludGVnZXI+MDwvaW50ZWdlcj4KCQkJCTwvZGljdD4KCQkJPC9hcnJheT4KCQk8L2Rp
+ Y3Q+CgkJPGtleT5jb20uYXBwbGUucHJpbnQuUGFnZUZvcm1hdC5QTUFkanVzdGVkUGFw
+ ZXJSZWN0PC9rZXk+CgkJPGRpY3Q+CgkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tl
+ dC5jcmVhdG9yPC9rZXk+CgkJCTxzdHJpbmc+Y29tLmFwcGxlLnByaW50aW5nbWFuYWdl
+ cjwvc3RyaW5nPgoJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycmF5
+ PC9rZXk+CgkJCTxhcnJheT4KCQkJCTxkaWN0PgoJCQkJCTxrZXk+Y29tLmFwcGxlLnBy
+ aW50LlBhZ2VGb3JtYXQuUE1BZGp1c3RlZFBhcGVyUmVjdDwva2V5PgoJCQkJCTxhcnJh
+ eT4KCQkJCQkJPHJlYWw+LTEuODAwMDAwMDAwMDAwMDAwZSswMTwvcmVhbD4KCQkJCQkJ
+ PHJlYWw+LTEuODAwMDAwMDAwMDAwMDAwZSswMTwvcmVhbD4KCQkJCQkJPHJlYWw+OC4y
+ NDAwMDAwMDAwMDAwMDBlKzAyPC9yZWFsPgoJCQkJCQk8cmVhbD41Ljc3MDAwMDAwMDAw
+ MDAwMGUrMDI8L3JlYWw+CgkJCQkJPC9hcnJheT4KCQkJCQk8a2V5PmNvbS5hcHBsZS5w
+ cmludC50aWNrZXQuY2xpZW50PC9rZXk+CgkJCQkJPHN0cmluZz5jb20uYXBwbGUucHJp
+ bnRpbmdtYW5hZ2VyPC9zdHJpbmc+CgkJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlj
+ a2V0Lm1vZERhdGU8L2tleT4KCQkJCQk8ZGF0ZT4yMDAzLTExLTEwVDIxOjI4OjIyWjwv
+ ZGF0ZT4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuc3RhdGVGbGFnPC9r
+ ZXk+CgkJCQkJPGludGVnZXI+MDwvaW50ZWdlcj4KCQkJCTwvZGljdD4KCQkJPC9hcnJh
+ eT4KCQk8L2RpY3Q+CgkJPGtleT5jb20uYXBwbGUucHJpbnQuUGFwZXJJbmZvLlBNUGFw
+ ZXJOYW1lPC9rZXk+CgkJPGRpY3Q+CgkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tl
dC5jcmVhdG9yPC9rZXk+CgkJCTxzdHJpbmc+Y29tLmFwcGxlLnByaW50LnBtLlBvc3RT
Y3JpcHQ8L3N0cmluZz4KCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0Lml0ZW1B
cnJheTwva2V5PgoJCQk8YXJyYXk+CgkJCQk8ZGljdD4KCQkJCQk8a2V5PmNvbS5hcHBs
- ZS5wcmludC5QYXBlckluZm8uUE1VbmFkanVzdGVkUGFnZVJlY3Q8L2tleT4KCQkJCQk8
- YXJyYXk+CgkJCQkJCTxyZWFsPjAuMDAwMDAwMDAwMDAwMDAwZSswMDwvcmVhbD4KCQkJ
- CQkJPHJlYWw+MC4wMDAwMDAwMDAwMDAwMDBlKzAwPC9yZWFsPgoJCQkJCQk8cmVhbD43
- LjgzMDAwMDAwMDAwMDAwMGUrMDI8L3JlYWw+CgkJCQkJCTxyZWFsPjUuNTkwMDAwMDAw
- MDAwMDAwZSswMjwvcmVhbD4KCQkJCQk8L2FycmF5PgoJCQkJCTxrZXk+Y29tLmFwcGxl
- LnByaW50LnRpY2tldC5jbGllbnQ8L2tleT4KCQkJCQk8c3RyaW5nPmNvbS5hcHBsZS5w
- cmludC5wbS5Qb3N0U2NyaXB0PC9zdHJpbmc+CgkJCQkJPGtleT5jb20uYXBwbGUucHJp
- bnQudGlja2V0Lm1vZERhdGU8L2tleT4KCQkJCQk8ZGF0ZT4yMDAwLTA3LTI4VDIyOjU3
- OjA0WjwvZGF0ZT4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuc3RhdGVG
- bGFnPC9rZXk+CgkJCQkJPGludGVnZXI+MTwvaW50ZWdlcj4KCQkJCTwvZGljdD4KCQkJ
- PC9hcnJheT4KCQk8L2RpY3Q+CgkJPGtleT5jb20uYXBwbGUucHJpbnQuUGFwZXJJbmZv
- LlBNVW5hZGp1c3RlZFBhcGVyUmVjdDwva2V5PgoJCTxkaWN0PgoJCQk8a2V5PmNvbS5h
- cHBsZS5wcmludC50aWNrZXQuY3JlYXRvcjwva2V5PgoJCQk8c3RyaW5nPmNvbS5hcHBs
- ZS5wcmludC5wbS5Qb3N0U2NyaXB0PC9zdHJpbmc+CgkJCTxrZXk+Y29tLmFwcGxlLnBy
- aW50LnRpY2tldC5pdGVtQXJyYXk8L2tleT4KCQkJPGFycmF5PgoJCQkJPGRpY3Q+CgkJ
- CQkJPGtleT5jb20uYXBwbGUucHJpbnQuUGFwZXJJbmZvLlBNVW5hZGp1c3RlZFBhcGVy
- UmVjdDwva2V5PgoJCQkJCTxhcnJheT4KCQkJCQkJPHJlYWw+LTEuODAwMDAwMDAwMDAw
- MDAwZSswMTwvcmVhbD4KCQkJCQkJPHJlYWw+LTEuODAwMDAwMDAwMDAwMDAwZSswMTwv
- cmVhbD4KCQkJCQkJPHJlYWw+OC4yNDAwMDAwMDAwMDAwMDBlKzAyPC9yZWFsPgoJCQkJ
- CQk8cmVhbD41Ljc3MDAwMDAwMDAwMDAwMGUrMDI8L3JlYWw+CgkJCQkJPC9hcnJheT4K
- CQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuY2xpZW50PC9rZXk+CgkJCQkJ
- PHN0cmluZz5jb20uYXBwbGUucHJpbnQucG0uUG9zdFNjcmlwdDwvc3RyaW5nPgoJCQkJ
- CTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5tb2REYXRlPC9rZXk+CgkJCQkJPGRh
- dGU+MjAwMC0wNy0yOFQyMjo1NzowNFo8L2RhdGU+CgkJCQkJPGtleT5jb20uYXBwbGUu
- cHJpbnQudGlja2V0LnN0YXRlRmxhZzwva2V5PgoJCQkJCTxpbnRlZ2VyPjE8L2ludGVn
- ZXI+CgkJCQk8L2RpY3Q+CgkJCTwvYXJyYXk+CgkJPC9kaWN0PgoJCTxrZXk+Y29tLmFw
- cGxlLnByaW50LlBhcGVySW5mby5wcGQuUE1QYXBlck5hbWU8L2tleT4KCQk8ZGljdD4K
- CQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNyZWF0b3I8L2tleT4KCQkJPHN0
- cmluZz5jb20uYXBwbGUucHJpbnQucG0uUG9zdFNjcmlwdDwvc3RyaW5nPgoJCQk8a2V5
- PmNvbS5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycmF5PC9rZXk+CgkJCTxhcnJheT4K
- CQkJCTxkaWN0PgoJCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LlBhcGVySW5mby5wcGQu
- UE1QYXBlck5hbWU8L2tleT4KCQkJCQk8c3RyaW5nPkE0PC9zdHJpbmc+CgkJCQkJPGtl
- eT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNsaWVudDwva2V5PgoJCQkJCTxzdHJpbmc+
- Y29tLmFwcGxlLnByaW50LnBtLlBvc3RTY3JpcHQ8L3N0cmluZz4KCQkJCQk8a2V5PmNv
- bS5hcHBsZS5wcmludC50aWNrZXQubW9kRGF0ZTwva2V5PgoJCQkJCTxkYXRlPjIwMDAt
- MDctMjhUMjI6NTc6MDRaPC9kYXRlPgoJCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRp
- Y2tldC5zdGF0ZUZsYWc8L2tleT4KCQkJCQk8aW50ZWdlcj4xPC9pbnRlZ2VyPgoJCQkJ
- PC9kaWN0PgoJCQk8L2FycmF5PgoJCTwvZGljdD4KCQk8a2V5PmNvbS5hcHBsZS5wcmlu
- dC50aWNrZXQuQVBJVmVyc2lvbjwva2V5PgoJCTxzdHJpbmc+MDAuMjA8L3N0cmluZz4K
- CQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQucHJpdmF0ZUxvY2s8L2tleT4KCQk8
- ZmFsc2UvPgoJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC50eXBlPC9rZXk+CgkJ
- PHN0cmluZz5jb20uYXBwbGUucHJpbnQuUGFwZXJJbmZvVGlja2V0PC9zdHJpbmc+Cgk8
- L2RpY3Q+Cgk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuQVBJVmVyc2lvbjwva2V5
- PgoJPHN0cmluZz4wMC4yMDwvc3RyaW5nPgoJPGtleT5jb20uYXBwbGUucHJpbnQudGlj
- a2V0LnByaXZhdGVMb2NrPC9rZXk+Cgk8ZmFsc2UvPgoJPGtleT5jb20uYXBwbGUucHJp
- bnQudGlja2V0LnR5cGU8L2tleT4KCTxzdHJpbmc+Y29tLmFwcGxlLnByaW50LlBhZ2VG
- b3JtYXRUaWNrZXQ8L3N0cmluZz4KPC9kaWN0Pgo8L3BsaXN0PgqGkoSZmRZOU0hvcml6
- b250YWxseUNlbnRlcmVkhpKokoSZmQ1OU1JpZ2h0TWFyZ2luhpKEm5ygniSGkoSZmRBO
- U0pvYkRpc3Bvc2l0aW9uhpKEmZkPTlNQcmludFNwb29sSm9ihpKEmZkITlNDb3BpZXOG
- koSbnISEAVOiAYaShJmZC05TUGFwZXJOYW1lhpKEmZkGaXNvLWE0hpKEmZkLTlNGaXJz
- dFBhZ2WGkoSbnLyiAYaShJmZFE5TVmVydGljYWxQYWdpbmF0aW9uhpKEm5ydnQCGkoSZ
- mQ1OU09yaWVudGF0aW9uhpKEm5ydnQCGkoSZmRlOU1ByaW50UmV2ZXJzZU9yaWVudGF0
- aW9uhpKikoSZmQpOU0xhc3RQYWdlhpKEm5yEl5eCf////4aShJmZC05TVG9wTWFyZ2lu
- hpKEm5ygniSGkoSZmQtOU1BhcGVyU2l6ZYaShJychIQMe19OU1NpemU9ZmZ9o4ECU4ED
- SoaGhg==
+ ZS5wcmludC5QYXBlckluZm8uUE1QYXBlck5hbWU8L2tleT4KCQkJCQk8c3RyaW5nPmlz
+ by1hNDwvc3RyaW5nPgoJCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5jbGll
+ bnQ8L2tleT4KCQkJCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludC5wbS5Qb3N0U2NyaXB0
+ PC9zdHJpbmc+CgkJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0Lm1vZERhdGU8
+ L2tleT4KCQkJCQk8ZGF0ZT4yMDAwLTA3LTI4VDIyOjU3OjA0WjwvZGF0ZT4KCQkJCQk8
+ a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuc3RhdGVGbGFnPC9rZXk+CgkJCQkJPGlu
+ dGVnZXI+MTwvaW50ZWdlcj4KCQkJCTwvZGljdD4KCQkJPC9hcnJheT4KCQk8L2RpY3Q+
+ CgkJPGtleT5jb20uYXBwbGUucHJpbnQuUGFwZXJJbmZvLlBNVW5hZGp1c3RlZFBhZ2VS
+ ZWN0PC9rZXk+CgkJPGRpY3Q+CgkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5j
+ cmVhdG9yPC9rZXk+CgkJCTxzdHJpbmc+Y29tLmFwcGxlLnByaW50LnBtLlBvc3RTY3Jp
+ cHQ8L3N0cmluZz4KCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0Lml0ZW1BcnJh
+ eTwva2V5PgoJCQk8YXJyYXk+CgkJCQk8ZGljdD4KCQkJCQk8a2V5PmNvbS5hcHBsZS5w
+ cmludC5QYXBlckluZm8uUE1VbmFkanVzdGVkUGFnZVJlY3Q8L2tleT4KCQkJCQk8YXJy
+ YXk+CgkJCQkJCTxyZWFsPjAuMDAwMDAwMDAwMDAwMDAwZSswMDwvcmVhbD4KCQkJCQkJ
+ PHJlYWw+MC4wMDAwMDAwMDAwMDAwMDBlKzAwPC9yZWFsPgoJCQkJCQk8cmVhbD43Ljgz
+ MDAwMDAwMDAwMDAwMGUrMDI8L3JlYWw+CgkJCQkJCTxyZWFsPjUuNTkwMDAwMDAwMDAw
+ MDAwZSswMjwvcmVhbD4KCQkJCQk8L2FycmF5PgoJCQkJCTxrZXk+Y29tLmFwcGxlLnBy
+ aW50LnRpY2tldC5jbGllbnQ8L2tleT4KCQkJCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmlu
+ dC5wbS5Qb3N0U2NyaXB0PC9zdHJpbmc+CgkJCQkJPGtleT5jb20uYXBwbGUucHJpbnQu
+ dGlja2V0Lm1vZERhdGU8L2tleT4KCQkJCQk8ZGF0ZT4yMDAwLTA3LTI4VDIyOjU3OjA0
+ WjwvZGF0ZT4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuc3RhdGVGbGFn
+ PC9rZXk+CgkJCQkJPGludGVnZXI+MTwvaW50ZWdlcj4KCQkJCTwvZGljdD4KCQkJPC9h
+ cnJheT4KCQk8L2RpY3Q+CgkJPGtleT5jb20uYXBwbGUucHJpbnQuUGFwZXJJbmZvLlBN
+ VW5hZGp1c3RlZFBhcGVyUmVjdDwva2V5PgoJCTxkaWN0PgoJCQk8a2V5PmNvbS5hcHBs
+ ZS5wcmludC50aWNrZXQuY3JlYXRvcjwva2V5PgoJCQk8c3RyaW5nPmNvbS5hcHBsZS5w
+ cmludC5wbS5Qb3N0U2NyaXB0PC9zdHJpbmc+CgkJCTxrZXk+Y29tLmFwcGxlLnByaW50
+ LnRpY2tldC5pdGVtQXJyYXk8L2tleT4KCQkJPGFycmF5PgoJCQkJPGRpY3Q+CgkJCQkJ
+ PGtleT5jb20uYXBwbGUucHJpbnQuUGFwZXJJbmZvLlBNVW5hZGp1c3RlZFBhcGVyUmVj
+ dDwva2V5PgoJCQkJCTxhcnJheT4KCQkJCQkJPHJlYWw+LTEuODAwMDAwMDAwMDAwMDAw
+ ZSswMTwvcmVhbD4KCQkJCQkJPHJlYWw+LTEuODAwMDAwMDAwMDAwMDAwZSswMTwvcmVh
+ bD4KCQkJCQkJPHJlYWw+OC4yNDAwMDAwMDAwMDAwMDBlKzAyPC9yZWFsPgoJCQkJCQk8
+ cmVhbD41Ljc3MDAwMDAwMDAwMDAwMGUrMDI8L3JlYWw+CgkJCQkJPC9hcnJheT4KCQkJ
+ CQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuY2xpZW50PC9rZXk+CgkJCQkJPHN0
+ cmluZz5jb20uYXBwbGUucHJpbnQucG0uUG9zdFNjcmlwdDwvc3RyaW5nPgoJCQkJCTxr
+ ZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5tb2REYXRlPC9rZXk+CgkJCQkJPGRhdGU+
+ MjAwMC0wNy0yOFQyMjo1NzowNFo8L2RhdGU+CgkJCQkJPGtleT5jb20uYXBwbGUucHJp
+ bnQudGlja2V0LnN0YXRlRmxhZzwva2V5PgoJCQkJCTxpbnRlZ2VyPjE8L2ludGVnZXI+
+ CgkJCQk8L2RpY3Q+CgkJCTwvYXJyYXk+CgkJPC9kaWN0PgoJCTxrZXk+Y29tLmFwcGxl
+ LnByaW50LlBhcGVySW5mby5wcGQuUE1QYXBlck5hbWU8L2tleT4KCQk8ZGljdD4KCQkJ
+ PGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNyZWF0b3I8L2tleT4KCQkJPHN0cmlu
+ Zz5jb20uYXBwbGUucHJpbnQucG0uUG9zdFNjcmlwdDwvc3RyaW5nPgoJCQk8a2V5PmNv
+ bS5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycmF5PC9rZXk+CgkJCTxhcnJheT4KCQkJ
+ CTxkaWN0PgoJCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LlBhcGVySW5mby5wcGQuUE1Q
+ YXBlck5hbWU8L2tleT4KCQkJCQk8c3RyaW5nPkE0PC9zdHJpbmc+CgkJCQkJPGtleT5j
+ b20uYXBwbGUucHJpbnQudGlja2V0LmNsaWVudDwva2V5PgoJCQkJCTxzdHJpbmc+Y29t
+ LmFwcGxlLnByaW50LnBtLlBvc3RTY3JpcHQ8L3N0cmluZz4KCQkJCQk8a2V5PmNvbS5h
+ cHBsZS5wcmludC50aWNrZXQubW9kRGF0ZTwva2V5PgoJCQkJCTxkYXRlPjIwMDAtMDct
+ MjhUMjI6NTc6MDRaPC9kYXRlPgoJCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tl
+ dC5zdGF0ZUZsYWc8L2tleT4KCQkJCQk8aW50ZWdlcj4xPC9pbnRlZ2VyPgoJCQkJPC9k
+ aWN0PgoJCQk8L2FycmF5PgoJCTwvZGljdD4KCQk8a2V5PmNvbS5hcHBsZS5wcmludC50
+ aWNrZXQuQVBJVmVyc2lvbjwva2V5PgoJCTxzdHJpbmc+MDAuMjA8L3N0cmluZz4KCQk8
+ a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQucHJpdmF0ZUxvY2s8L2tleT4KCQk8ZmFs
+ c2UvPgoJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC50eXBlPC9rZXk+CgkJPHN0
+ cmluZz5jb20uYXBwbGUucHJpbnQuUGFwZXJJbmZvVGlja2V0PC9zdHJpbmc+Cgk8L2Rp
+ Y3Q+Cgk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuQVBJVmVyc2lvbjwva2V5PgoJ
+ PHN0cmluZz4wMC4yMDwvc3RyaW5nPgoJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0
+ LnByaXZhdGVMb2NrPC9rZXk+Cgk8ZmFsc2UvPgoJPGtleT5jb20uYXBwbGUucHJpbnQu
+ dGlja2V0LnR5cGU8L2tleT4KCTxzdHJpbmc+Y29tLmFwcGxlLnByaW50LlBhZ2VGb3Jt
+ YXRUaWNrZXQ8L3N0cmluZz4KPC9kaWN0Pgo8L3BsaXN0PgqGkoSZmQ9OU1ByaW50QWxs
+ UGFnZXOGkpyShJmZFU5TSG9yaXpvbmFsUGFnaW5hdGlvboaShJ2cn50AhpKEmZkITlND
+ b3BpZXOGkoSdnISEAVOhAYaShJmZFk5TSG9yaXpvbnRhbGx5Q2VudGVyZWSGkqaShJmZ
+ CU5TUHJpbnRlcoaShISECU5TUHJpbnRlcgCUkoSZmQEghoaShJmZC05TUGFwZXJOYW1l
+ hpKEmZkGaXNvLWE0hpKEmZkPTlNTY2FsaW5nRmFjdG9yhpKEnZyEhAFmowGGkoSZmQ1O
+ U1JpZ2h0TWFyZ2luhpKEnZy8oySGkoSZmQ1OU0pvYkZlYXR1cmVzhpKElpcAhpKEmZkM
+ TlNMZWZ0TWFyZ2luhpKEnZy8oySGkoSZmQ5OU0JvdHRvbU1hcmdpboaShJ2cvKMkhpKE
+ mZkLTlNUb3BNYXJnaW6GkoSdnLyjJIaShJmZCk5TTGFzdFBhZ2WGkoSdnISXl4J/////
+ hpKEmZkLTlNGaXJzdFBhZ2WGkoSdnLKhAYaShJmZDU5TT3JpZW50YXRpb26GkoSdnJ+d
+ AIaGhg==
RowAlign0
@@ -1055,7 +1074,7 @@ Sheet}
WindowInfoFrame
- {{1998, 271}, {559, 717}}
+ {{38, 272}, {559, 717}}VisibleRegion{{-10, 0}, {544, 640}}Zoom
diff --git a/NovaTools/English.lproj/Resource Types.strings b/NovaTools/English.lproj/Resource Types.strings
index f492db88e1886fd6a94802b61434a57173647fab..4a080e08ebc0aee48691b885d8f68f42e4fd6790 100644
GIT binary patch
delta 38
qcmdnT@qlB4Afse5Loq`sLoS07g93vs5Gyf&ME)@3ZsuS#V+H`OO$avt
delta 12
TcmaFBv5#YeAme6ZMqOqA9Y6z!
diff --git a/NovaTools/NovaWindowController.m b/NovaTools/NovaWindowController.m
index 6b6eae6..abf209b 100644
--- a/NovaTools/NovaWindowController.m
+++ b/NovaTools/NovaWindowController.m
@@ -4,6 +4,8 @@
#import "ColrWindowController.h"
#import "CronWindowController.h"
#import "DescWindowController.h"
+#import "MisnWindowController.h"
+#import "ShipWindowController.h"
@implementation NovaWindowController
diff --git a/NovaTools/Structs.h b/NovaTools/Structs.h
index f62ea08..8e7b657 100644
--- a/NovaTools/Structs.h
+++ b/NovaTools/Structs.h
@@ -7,21 +7,19 @@
// see http://developer.apple.com/techpubs/macosx/DeveloperTools/MachORuntime/2rt_powerpc_abi/PowerPC_Data_Alignment.html
// align=reset is at the bottom of the file.
-typedef struct RLEPixelData
+typedef struct NovaControlBits
{
- // 'rl#' resource
- short width; // pixel width (max for all frames)
- short height; // pixel height (max for all frames)
- short depth; // bit depth (8/16/32)
- short palette; // color table 'clut' ID (0 for default)
- short nframes; // number of frames in this resource
- short reserved1;
- short reserved2;
- short reserved3;
- char tokens[1]; // the RLE token data (variable size array)
-} RLEPixelData;
+ // 10,000 bits for ncbs, could be made faster by aligning to word boundries? (using longs) but would require padding
+ char bits[1250]; // access bit 777 thus: bits[777/8] >> (777 % 8)) & 0x01
+ // or: bits[777/8] & (0x01 << (777 % 8))
+} NovaControlBits;
-#define kRLEResourceHeaderSize (sizeof(RLEPixelData) - 1)
+typedef struct BoomRec
+{
+ short FrameAdvance; // 100 = normal speed, less is slower, higher faster
+ short SoundIndex; // 0-63 index, mapping to 300-363 resID, -1 == no sound
+ short GraphicIndex; // 0-63 index, mapping to 400-463 resID
+} BoomRec;
typedef struct CharRec
{
@@ -44,6 +42,60 @@ typedef struct CharRec
short UnusedA[8];
} CharRec;
+typedef struct ColrRec
+{
+ long ButtonUp;
+ long ButtonDown;
+ long ButtonGrey;
+ char MenuFont[64];
+ short MenuFontSize;
+ long MenuColor1;
+ long MenuColor2;
+ long GridBright;
+ long GridDim;
+ // p2c: Structs.p, line 696: Warning: Symbol 'RECT' is not defined [221]
+ Rect ProgArea;
+ long ProgBright;
+ long ProgDim;
+ long ProgOutline;
+
+ short Button1x;
+ short Button1y;
+ short Button2x;
+ short Button2y;
+ short Button3x;
+ short Button3y;
+ short Button4x;
+ short Button4y;
+ short Button5x;
+ short Button5y;
+ short Button6x;
+ short Button6y;
+
+ long FloatingMap;
+ long ListText;
+ long ListBkgnd;
+ long ListHilite;
+ long EscortHilite;
+
+ char ButtonFont[64];
+ short ButtonFontSz;
+
+ short LogoX;
+ short LogoY;
+
+ short RolloverX;
+ short RolloverY;
+
+ short Slide1x;
+ short Slide1y;
+ short Slide2x;
+ short Slide2y;
+ short Slide3x;
+ short Slide3y;
+
+} ColrRec;
+
typedef struct CronRec
{
short FirstDay;
@@ -70,232 +122,6 @@ typedef struct CronRec
short GovtNewsString[4];
} CronRec;
-typedef struct SpinRec
-{
- short SpritesID;
- short MasksID;
- short xSize;
- short ySize;
- short nx;
- short ny;
-} SpinRec;
-
-typedef struct ShanRec
-{
- short BaseImageID;
- short BaseMaskID;
- short BaseSetCount;
- short BaseXSize;
- short BaseYSize;
- short BaseTransp;
-
- short AltImageID;
- short AltMaskID;
- short AltSetCount;
- short AltXSize;
- short AltYSize;
-
- short GlowImageID;
- short GlowMaskID;
- short GlowXSize;
- short GlowYSize;
-
- short LightImageID;
- short LightMaskID;
- short LightXSize;
- short LightYSize;
-
- short WeapImageID;
- short WeapMaskID;
- short WeapXSize;
- short WeapYSize;
-
- short Flags;
-
- short AnimDelay;
- short WeapDecay;
- short FramesPer;
- short BlinkMode;
- short BlinkA;
- short BlinkB;
- short BlinkC;
- short BlinkD;
-
- short ShieldImgID;
- short ShieldMaskID;
- short ShieldXSize;
- short ShieldYSize;
-
- short GunPosX[4];
- short GunPosY[4];
- short TurretPosX[4];
- short TurretPosY[4];
- short GuidedPosX[4];
- short GuidedPosY[4];
- short BeamPosX[4];
- short BeamPosY[4];
-
- short UpCompressX;
- short UpCompressY;
- short DnCompressX;
- short DnCompressY;
-
- short GunPosZ[4];
- short TurretPosZ[4];
- short GuidedPosZ[4];
- short BeamPosZ[4];
-
- short UnusedA[8];
-
-} ShanRec;
-
-typedef struct SystRec
-{
- short xPos;
- short yPos;
- short con[16];
- short nav[16];
- short DudeTypes[8];
- short Probs[8];
- short AvgShips;
- short Govt;
- short Message;
- short Asteroids;
- short Interference;
- short Person[8];
- short PersonProb[8];
- long BkgndColor;
- short Murk;
- short AstTypes;
- char Visiblility[256];
- short ReinfFleet;
- short ReinfTime;
- short ReinfIntrval;
- short UnusedA[8];
-} SystRec;
-
-typedef struct SpobRec
-{
- short xPos;
- short yPos;
- short spobType;
- long Flags;
- short Tribute;
- short TechLevel;
- short SpecialTech1;
- short SpecialTech2;
- short SpecialTech3;
- short Govt;
- short MinCoolness;
- short CustPicID;
- short CustSndID;
- short DefDude;
- short DefCount;
- short Flags2;
- short AnimDelay;
- short Frame0Bias;
- short HyperLink[8];
- // OnDominate: packed array[0..254] of char;
- // OnRelease: packed array[0..254] of char;
- char cdata[510];
- long Fee;
- short Gravity;
- short Weapon;
- long Strength;
- short DeadType;
- short DeadTime;
- short ExplodType;
- // OnDestroy : packed array[0..254] of char;
- // OnRegen : packed array[0..254] of char;
- char cdata2[510];
- short SpecialTech4;
- short SpecialTech5;
- short SpecialTech6;
- short SpecialTech7;
- short SpecialTech8;
- short UnusedA[8];
-} SpobRec;
-
-typedef struct ShipRec
-{
- short holds;
- short Shield;
- short Accel;
- short Speed;
- short Maneuver;
- short Fuel;
- short freeMass;
- short Armor;
- short ShieldRegen;
- short WType[4];
- short WCount[4];
- short Ammo[4];
- short MaxGun;
- short MaxTur;
- short TechLevel;
- long Cost;
- short DeathDelay;
- short ArmorRech;
- short Explode1;
- short Explode2;
- short DispWeight;
- short Mass;
- short Length;
- short InherentAI;
- short Crew;
- short Strength;
- short InherentGovt;
- short Flags;
- short PodCount;
- short DefaultItems[4];
- short ItemCount[4];
- short FuelRegen;
- short SkillVar;
- short Flags2;
- long Contributes0;
- long Contributes1;
- // Availability: packed array[0..254] of char;
- // AppearOn: packed array[0..254] of char;
- // OnPurchase: packed array[0..255] of char;
-
- char cdata1[766];
-
- short Deionize;
- short IonizeMax;
- short KeyCarried;
- short DefaultItems2[4];
- short ItemCount2[4];
- long Require0;
- long Require1;
-
- short BuyRandom;
- short HireRandom;
-
- short unusedBlock[34];
-
- // OnCapture: packed array[0..254] of char;
- // OnRetire: packed array[0..254] of char;
- // ShortName: packed array[0..63] of char;
- // CommName: packed array[0..31] of char;
- // LongName: packed array[0..127] of char;
- // MovieFile: packed array[0..31] of char;
-
- char cdata2[766];
-
- short WType2[4];
- short WCount2[4];
- short Ammo2[4];
-
- // SubTitle: packed array[0..63] of char;
- char cdata3[64];
- short Flags3;
- short UpgradeTo;
- long EscUpgrdCost;
- long EscSellValue;
- short EscortType;
- short UnusedA[8];
-} ShipRec;
-
typedef struct DescRec
{
char Description[1];
@@ -308,99 +134,10 @@ typedef struct DescCodaRec
short Flags;
} DescCodaRec;
-typedef struct WeapRec
+typedef struct DeqtRec
{
- short Reload;
- short Count;
- short MassDmg;
- short EnergyDmg;
- short Guidance;
- short Speed;
- short AmmoType;
- short Graphic;
- short Inaccuracy;
- short Sound;
- short Impact;
- short ExplodType;
- short ProxRadius;
- short BlastRadius;
short Flags;
- short Seeker;
- short SmokeSet;
- short Decay;
- short Particles;
- short PartVel;
- short PartLifeMin;
- short PartLifeMax;
- long PartColor;
- short BeamLength;
- short BeamWidth;
- short Falloff;
- long BeamColor;
- long CoronaColor;
- short SubCount;
- short SubType;
- short SubTheta;
- short SubLimit;
- short ProxSafety;
- short Flags2;
- short Ionization;
- short HitParticles;
- short HitPartLife;
- short HitPartVel;
- long HitPartColor;
- short Recoil;
- short ExitType;
- short BurstCount;
- short BurstReload;
- short JamVuln1;
- short JamVuln2;
- short JamVuln3;
- short JamVuln4;
- short Flags3;
- short Durability;
- short GuidedTurn;
- short MaxAmmo;
- short LiDensity;
- short LiAmplitude;
- long IonizeColor;
- short UnusedA[8];
-} WeapRec;
-
-typedef struct OutfRec
-{
- short DispWeight;
- short Mass;
- short TechLevel;
- short ModType;
- short ModVal;
- short Max;
- short Flags;
- long Cost;
- short ModType2;
- short ModVal2;
- short ModType3;
- short ModVal3;
- short ModType4;
- short ModVal4;
- long Contributes0;
- long Contributes1;
- long Require0;
- long Require1;
- // Availability: packed array[0..254] of char;
- // OnPurchase: packed array[0..254] of char;
- // OnSell: packed array[0..254] of char;
- // ShortName: packed array[0..63] of char;
- // LCName: packed array[0..63] of char;
- // LCPlural: packed array[0..64] of char;
- char cdata[958];
- short ItemClass;
- short ScanMask;
- short BuyRandom;
- short RequireGovt;
- short UnusedA[8];
-} OutfRec;
-
+} DeqtRec;
typedef struct DudeRec
{
@@ -413,6 +150,58 @@ typedef struct DudeRec
short UnusedA[8];
} DudeRec;
+typedef struct FletRec
+{
+ short LeadShipType;
+ short EscortShipType[4];
+ short EscortMin[4];
+ short EscortMax[4];
+ short Govt;
+ short LinkSyst;
+ char ActivateOn[256];
+ short Quote;
+ short Flags;
+ short UnusedA[8];
+} FletRec;
+
+typedef struct IntfRec
+{
+ long BrightText;
+ long DimText;
+ Rect RadarArea;
+ long BrightRadar;
+ long DimRadar;
+ Rect ShieldArea;
+ long Shield;
+ Rect ArmorArea;
+ long Armor;
+ Rect FuelArea;
+ long FuelFull;
+ long FuelPartial;
+ Rect NavArea;
+ Rect WeapArea;
+ Rect TargArea;
+ Rect CargoArea;
+ char StatusFont[64];
+ short StatFontSize;
+ short SubtitleSize;
+ short StatusBkgnd;
+} IntfRec;
+
+typedef struct JunkRec
+{
+ short SoldAt[8];
+ short BoughtAt[8];
+ short BasePrice;
+ short Flags;
+ short ScanMask;
+ // LCName: packed array[0..63] of char;
+ // Abbrev: packed array[0..63] of char;
+ // BuyOn: packed array[0..254] of char;
+ // SellOn: packed array[0..254] of char;
+ char cdata[638];
+} JunkRec;
+
typedef struct GovtRec
{
short VoiceType;
@@ -514,6 +303,63 @@ typedef struct MisnRec
short UnusedA[8];
} MisnRec;
+typedef struct NebuRec
+{
+ short XPos;
+ short YPos;
+ short XSize;
+ short YSize;
+ // ActiveOn: packed array[0..254] of char;
+ // OnExplore: packed array[0..254] of char;
+ char cdata[510];
+ short UnusedA[8];
+} NebuRec;
+
+typedef struct OopsRec
+{
+ short Stellar;
+ short Commodity;
+ short PriceDelta;
+ short Duration;
+ short Freq;
+ char ActivateOn[256];
+ short UnusedA[8];
+} OopsRec;
+
+typedef struct OutfRec
+{
+ short DispWeight;
+ short Mass;
+ short TechLevel;
+ short ModType;
+ short ModVal;
+ short Max;
+ short Flags;
+ long Cost;
+ short ModType2;
+ short ModVal2;
+ short ModType3;
+ short ModVal3;
+ short ModType4;
+ short ModVal4;
+ long Contributes0;
+ long Contributes1;
+ long Require0;
+ long Require1;
+ // Availability: packed array[0..254] of char;
+ // OnPurchase: packed array[0..254] of char;
+ // OnSell: packed array[0..254] of char;
+ // ShortName: packed array[0..63] of char;
+ // LCName: packed array[0..63] of char;
+ // LCPlural: packed array[0..64] of char;
+ char cdata[958];
+ short ItemClass;
+ short ScanMask;
+ short BuyRandom;
+ short RequireGovt;
+ short UnusedA[8];
+} OutfRec;
+
typedef struct PersRec
{
short LinkSyst;
@@ -542,78 +388,6 @@ typedef struct PersRec
short UnusedA[8];
} PersRec;
-typedef struct DeqtRec
-{
- short Flags;
-} DeqtRec;
-
-typedef struct YearRec
-{
- short Day;
- short Month;
- short Year;
- char Prefix[16];
- char Suffix[15];
-} YearRec;
-
-typedef struct OopsRec
-{
- short Stellar;
- short Commodity;
- short PriceDelta;
- short Duration;
- short Freq;
- char ActivateOn[256];
- short UnusedA[8];
-} OopsRec;
-
-typedef struct NebuRec
-{
- short XPos;
- short YPos;
- short XSize;
- short YSize;
- // ActiveOn: packed array[0..254] of char;
- // OnExplore: packed array[0..254] of char;
- char cdata[510];
- short UnusedA[8];
-} NebuRec;
-
-typedef struct BoomRec
-{
- short FrameAdvance; // 100 = normal speed, less is slower, higher faster
- short SoundIndex; // 0-63 index, mapping to 300-363 resID, -1 == no sound
- short GraphicIndex; // 0-63 index, mapping to 400-463 resID
-} BoomRec;
-
-typedef struct FletRec
-{
- short LeadShipType;
- short EscortShipType[4];
- short EscortMin[4];
- short EscortMax[4];
- short Govt;
- short LinkSyst;
- char ActivateOn[256];
- short Quote;
- short Flags;
- short UnusedA[8];
-} FletRec;
-
-typedef struct JunkRec
-{
- short SoldAt[8];
- short BoughtAt[8];
- short BasePrice;
- short Flags;
- short ScanMask;
- // LCName: packed array[0..63] of char;
- // Abbrev: packed array[0..63] of char;
- // BuyOn: packed array[0..254] of char;
- // SellOn: packed array[0..254] of char;
- char cdata[638];
-} JunkRec;
-
typedef struct RankRec
{
short Weight;
@@ -645,82 +419,314 @@ typedef struct RoidRec
short UnusedA[8];
} RoidRec;
-typedef struct ColrRec
+typedef struct RLEPixelData
{
- long ButtonUp;
- long ButtonDown;
- long ButtonGrey;
- char MenuFont[64];
- short MenuFontSize;
- long MenuColor1;
- long MenuColor2;
- long GridBright;
- long GridDim;
- // p2c: Structs.p, line 696: Warning: Symbol 'RECT' is not defined [221]
- Rect ProgArea;
- long ProgBright;
- long ProgDim;
- long ProgOutline;
+ // 'rl#' resource
+ short width; // pixel width (max for all frames)
+ short height; // pixel height (max for all frames)
+ short depth; // bit depth (8/16/32)
+ short palette; // color table 'clut' ID (0 for default)
+ short nframes; // number of frames in this resource
+ short reserved1;
+ short reserved2;
+ short reserved3;
+ char tokens[1]; // the RLE token data (variable size array)
+} RLEPixelData;
- short Button1x;
- short Button1y;
- short Button2x;
- short Button2y;
- short Button3x;
- short Button3y;
- short Button4x;
- short Button4y;
- short Button5x;
- short Button5y;
- short Button6x;
- short Button6y;
+#define kRLEResourceHeaderSize (sizeof(RLEPixelData) - 1)
- long FloatingMap;
- long ListText;
- long ListBkgnd;
- long ListHilite;
- long EscortHilite;
-
- char ButtonFont[64];
- short ButtonFontSz;
-
- short LogoX;
- short LogoY;
-
- short RolloverX;
- short RolloverY;
-
- short Slide1x;
- short Slide1y;
- short Slide2x;
- short Slide2y;
- short Slide3x;
- short Slide3y;
-
-} ColrRec;
-
-typedef struct IntfRec
+typedef struct ShanRec
{
- long BrightText;
- long DimText;
- Rect RadarArea;
- long BrightRadar;
- long DimRadar;
- Rect ShieldArea;
- long Shield;
- Rect ArmorArea;
- long Armor;
- Rect FuelArea;
- long FuelFull;
- long FuelPartial;
- Rect NavArea;
- Rect WeapArea;
- Rect TargArea;
- Rect CargoArea;
- char StatusFont[64];
- short StatFontSize;
- short SubtitleSize;
- short StatusBkgnd;
-} IntfRec;
+ short BaseImageID;
+ short BaseMaskID;
+ short BaseSetCount;
+ short BaseXSize;
+ short BaseYSize;
+ short BaseTransp;
+
+ short AltImageID;
+ short AltMaskID;
+ short AltSetCount;
+ short AltXSize;
+ short AltYSize;
+
+ short GlowImageID;
+ short GlowMaskID;
+ short GlowXSize;
+ short GlowYSize;
+
+ short LightImageID;
+ short LightMaskID;
+ short LightXSize;
+ short LightYSize;
+
+ short WeapImageID;
+ short WeapMaskID;
+ short WeapXSize;
+ short WeapYSize;
+
+ short Flags;
+
+ short AnimDelay;
+ short WeapDecay;
+ short FramesPer;
+ short BlinkMode;
+ short BlinkA;
+ short BlinkB;
+ short BlinkC;
+ short BlinkD;
+
+ short ShieldImgID;
+ short ShieldMaskID;
+ short ShieldXSize;
+ short ShieldYSize;
+
+ short GunPosX[4];
+ short GunPosY[4];
+ short TurretPosX[4];
+ short TurretPosY[4];
+ short GuidedPosX[4];
+ short GuidedPosY[4];
+ short BeamPosX[4];
+ short BeamPosY[4];
+
+ short UpCompressX;
+ short UpCompressY;
+ short DnCompressX;
+ short DnCompressY;
+
+ short GunPosZ[4];
+ short TurretPosZ[4];
+ short GuidedPosZ[4];
+ short BeamPosZ[4];
+
+ short UnusedA[8];
+
+} ShanRec;
+
+typedef struct ShipRec
+{
+ short holds;
+ short Shield;
+ short Accel;
+ short Speed;
+ short Maneuver;
+ short Fuel;
+ short freeMass;
+ short Armor;
+ short ShieldRegen;
+ short WType[4];
+ short WCount[4];
+ short Ammo[4];
+ short MaxGun;
+ short MaxTur;
+ short TechLevel;
+ long Cost;
+ short DeathDelay;
+ short ArmorRech;
+ short Explode1;
+ short Explode2;
+ short DispWeight;
+ short Mass;
+ short Length;
+ short InherentAI;
+ short Crew;
+ short Strength;
+ short InherentGovt;
+ short Flags;
+ short PodCount;
+ short DefaultItems[4];
+ short ItemCount[4];
+ short FuelRegen;
+ short SkillVar;
+ short Flags2;
+ long Contributes0;
+ long Contributes1;
+ // Availability: packed array[0..254] of char;
+ // AppearOn: packed array[0..254] of char;
+ // OnPurchase: packed array[0..255] of char;
+
+ char cdata1[766];
+
+ short Deionize;
+ short IonizeMax;
+ short KeyCarried;
+ short DefaultItems2[4];
+ short ItemCount2[4];
+ long Require0;
+ long Require1;
+
+ short BuyRandom;
+ short HireRandom;
+
+ short unusedBlock[34];
+
+ // OnCapture: packed array[0..254] of char;
+ // OnRetire: packed array[0..254] of char;
+ // ShortName: packed array[0..63] of char;
+ // CommName: packed array[0..31] of char;
+ // LongName: packed array[0..127] of char;
+ // MovieFile: packed array[0..31] of char;
+
+ char cdata2[766];
+
+ short WType2[4];
+ short WCount2[4];
+ short Ammo2[4];
+
+ // SubTitle: packed array[0..63] of char;
+ char cdata3[64];
+ short Flags3;
+ short UpgradeTo;
+ long EscUpgrdCost;
+ long EscSellValue;
+ short EscortType;
+ short UnusedA[8];
+} ShipRec;
+
+typedef struct SpinRec
+{
+ short SpritesID;
+ short MasksID;
+ short xSize;
+ short ySize;
+ short nx;
+ short ny;
+} SpinRec;
+
+typedef struct SpobRec
+{
+ short xPos;
+ short yPos;
+ short spobType;
+ long Flags;
+ short Tribute;
+ short TechLevel;
+ short SpecialTech1;
+ short SpecialTech2;
+ short SpecialTech3;
+ short Govt;
+ short MinCoolness;
+ short CustPicID;
+ short CustSndID;
+ short DefDude;
+ short DefCount;
+ short Flags2;
+ short AnimDelay;
+ short Frame0Bias;
+ short HyperLink[8];
+ // OnDominate: packed array[0..254] of char;
+ // OnRelease: packed array[0..254] of char;
+ char cdata[510];
+ long Fee;
+ short Gravity;
+ short Weapon;
+ long Strength;
+ short DeadType;
+ short DeadTime;
+ short ExplodType;
+ // OnDestroy : packed array[0..254] of char;
+ // OnRegen : packed array[0..254] of char;
+ char cdata2[510];
+ short SpecialTech4;
+ short SpecialTech5;
+ short SpecialTech6;
+ short SpecialTech7;
+ short SpecialTech8;
+ short UnusedA[8];
+} SpobRec;
+
+typedef struct SystRec
+{
+ short xPos;
+ short yPos;
+ short con[16];
+ short nav[16];
+ short DudeTypes[8];
+ short Probs[8];
+ short AvgShips;
+ short Govt;
+ short Message;
+ short Asteroids;
+ short Interference;
+ short Person[8];
+ short PersonProb[8];
+ long BkgndColor;
+ short Murk;
+ short AstTypes;
+ char Visiblility[256];
+ short ReinfFleet;
+ short ReinfTime;
+ short ReinfIntrval;
+ short UnusedA[8];
+} SystRec;
+
+typedef struct WeapRec
+{
+ short Reload;
+ short Count;
+ short MassDmg;
+ short EnergyDmg;
+ short Guidance;
+ short Speed;
+ short AmmoType;
+ short Graphic;
+ short Inaccuracy;
+ short Sound;
+ short Impact;
+ short ExplodType;
+ short ProxRadius;
+ short BlastRadius;
+ short Flags;
+ short Seeker;
+ short SmokeSet;
+ short Decay;
+ short Particles;
+ short PartVel;
+ short PartLifeMin;
+ short PartLifeMax;
+ long PartColor;
+ short BeamLength;
+ short BeamWidth;
+ short Falloff;
+ long BeamColor;
+ long CoronaColor;
+ short SubCount;
+ short SubType;
+ short SubTheta;
+ short SubLimit;
+ short ProxSafety;
+ short Flags2;
+ short Ionization;
+ short HitParticles;
+ short HitPartLife;
+ short HitPartVel;
+ long HitPartColor;
+ short Recoil;
+ short ExitType;
+ short BurstCount;
+ short BurstReload;
+ short JamVuln1;
+ short JamVuln2;
+ short JamVuln3;
+ short JamVuln4;
+ short Flags3;
+ short Durability;
+ short GuidedTurn;
+ short MaxAmmo;
+ short LiDensity;
+ short LiAmplitude;
+ long IonizeColor;
+ short UnusedA[8];
+} WeapRec;
+
+typedef struct YearRec
+{
+ short Day;
+ short Month;
+ short Year;
+ char Prefix[16];
+ char Suffix[15];
+} YearRec;
#pragma options align=reset
\ No newline at end of file
diff --git a/NovaTools/boom/BoomWindowController.h b/NovaTools/boom/BoomWindowController.h
index 6463047..e784a97 100644
--- a/NovaTools/boom/BoomWindowController.h
+++ b/NovaTools/boom/BoomWindowController.h
@@ -35,7 +35,7 @@ enum // boom defaults
- (void)update;
- (void)controlTextDidChange:(NSNotification *)notification;
-- (IBAction)toggleSilence:(id)sender;
+- (IBAction)setSilent:(id)sender;
- (IBAction)playSound:(id)sender;
@end
diff --git a/NovaTools/boom/BoomWindowController.m b/NovaTools/boom/BoomWindowController.m
index 0076b62..30af5e2 100644
--- a/NovaTools/boom/BoomWindowController.m
+++ b/NovaTools/boom/BoomWindowController.m
@@ -111,11 +111,9 @@
[self setDocumentEdited:[resource isDirty]];
}
-- (IBAction)toggleSilence:(id)sender
+- (IBAction)setSilent:(id)sender
{
silent = ![soundButton state];
- [soundField setEnabled:!silent];
- [playButton setEnabled:!silent];
[resource touch];
[self setDocumentEdited:YES];
}
diff --git a/NovaTools/boom/English.lproj/boom.nib/classes.nib b/NovaTools/boom/English.lproj/boom.nib/classes.nib
index a853176..9d69c4b 100644
--- a/NovaTools/boom/English.lproj/boom.nib/classes.nib
+++ b/NovaTools/boom/English.lproj/boom.nib/classes.nib
@@ -1,7 +1,7 @@
{
IBClasses = (
{
- ACTIONS = {playSound = id; toggleSilence = id; };
+ ACTIONS = {playSound = id; setSilent = id; };
CLASS = BoomWindowController;
LANGUAGE = ObjC;
OUTLETS = {
@@ -16,7 +16,7 @@
},
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
{
- ACTIONS = {toggleResID = id; };
+ ACTIONS = {};
CLASS = NovaWindowController;
LANGUAGE = ObjC;
SUPERCLASS = NSWindowController;
diff --git a/NovaTools/boom/English.lproj/boom.nib/info.nib b/NovaTools/boom/English.lproj/boom.nib/info.nib
index 3517477..d11da9b 100644
--- a/NovaTools/boom/English.lproj/boom.nib/info.nib
+++ b/NovaTools/boom/English.lproj/boom.nib/info.nib
@@ -3,14 +3,24 @@
IBDocumentLocation
- 86 100 356 240 0 0 1024 746
+ 17 87 357 296 0 0 1280 1002 IBFramework Version
- 283.0
+ 326.0
+ IBLockedObjects
+
+ 41
+ 30
+ 37
+ 38
+ 39
+ 22
+ 49
+ IBOpenObjects5IBSystem Version
- 6G30
+ 7A179
diff --git a/NovaTools/boom/English.lproj/boom.nib/objects.nib b/NovaTools/boom/English.lproj/boom.nib/objects.nib
index 14eb620fea7517b899134b93939c751a9c401168..0226f44be746dc6813de97cd28c4cae2e26b5669 100644
GIT binary patch
literal 5515
zcma(V3vg3a_P!(yDJ|WW@)@uL(NTm_K1KXhl+Z$@LIaZeVJoYz$tyg~&*T-_omEM=
zdE@S=%f^yzWH$pSSOUX>JB~s@KyegZWknW6<*U#qu6$CP)duOuDa?uO^-`%WxA+{5ps-Do71JwkXT$t
zsc8u-0iQlOrk$D`ND62!B_#V73hh)FJE%Gk@I55^J%J@P0lyLoc)e0cjj2?S3lchZ
zb&H||{Djhcr^~<@L#fs2dQg^@z^K6KnkR*W0l!BIk@h(KQ#_U=w9o-pvvKL_)VC;N
zlUJG+3W;sNuAkGT58IRd;`F6>DjB_=5R!_)6%k5`CYKR1xh$TF$M8ojvfJ$-0ua(d
zr%P9=M)G>6^5q2+(cYo0K!lpkf6BkP8hT$vGd;<;h=_bm^k`%C69(WxF;PSe>I4Cr1
zS}^F9>~p8r+JjS$p5vP*l%<#L#V7SFA
zDw4-OHxO1_?vNZ*?29YMPr4%6V6eIDmHeVl3eV+Y8!}Rd8%ovHG+aiimduCoAt6S(asDiaH1}scC`Ru0MvduPIO+Xcf368>CjH
zR+hY;Vce287?zC98yg`zhk#7@zeFOe!3+-+YT^#g^1-Ql)~<~Xdh&uJN=%?jx-%Br
zz{6x4HM<=S5R7Y}Cg2Ugx=CB9S&vSus|_6DQ^5_T3aC{rx}R7W3bgn=995;e(`IUF
zZWaU;$JVa50khbxuU?dY5p6p`99%i>eu5yx>8d1AAx^i&=__EO85iuji8c^w4F-Y_
z1gqjZ;@dVxgypkHbm<-ki_wjG?1G{^*v7ZVV;F>bDDn}Gd0^tx_To}1gy9h*bm*h-
zd7^ufSaWCGE*bUX=E0tejjq(Y>I)o|F?}d7qF+
znGOr!-U#r^oM)Vy5AX=U?9+sl|CJD%2Rvy8;MY5Qzh*~HoM%UlpJ!hkJI4+i_ai6%
zqtC;;!!UpF^Y7Tso!>B@Z!34mCxBh;Xb*wzZ%0|Bm`V?&d
z^8B`S2if|)XW04=0CMjz?##kjK3)en?SDDR2G{Nede7Rup;QVpd
zY1X>o1RMP5K1TY#2t0@#>Dzal?i2i>>sz*X;|W&gKfuUM_zh%KW5-wQg|0Jwg5PcZ
zmW9*bFnjA4j7;5v^rIU(j5(tL(J3J!=bU`OIF*mo|!CGao@T1^Vk-Kk8u{yBS-5>gv#m?=;3%pJ42_`x&cy?f@&j({l{y
zhdz6(hiy5>`UEfkld;enU$ct($G$Szif03T;fp;ztcx-B1_0i#2CGkq30
z_}4;N4$sj!Jm+1U=PKHW{_FqaQbKMnCdM7ICZwJ11k(ppJUofQ9?lbB16Fldg}}ZJ
zX*m0M_e!V)qXU5tujya`gMum8gLAA*f=!2rSMZ(IaoF*Z?_3w{WGNmO3i)AWDm2g`uyC|BMSWKlNPNGlnoY;Eg!v0Ya!%3*TreQu7SUo}Nu$m6!nZ0G-T&B9
z0@*tj-vQ-ej0#mykb;}KurRy<=(rE&4ZKP@^VXFsmF}&=u6K9zsvWv7s~z5oYw_;O
ziiQt)lzjU0A@E+t?Vs(XhyM0u)`f>N-a2z6$Mi?9YVYIRglD-4zbX3Iu!sg0(a<9M
zbbD;Sq|X>Kt{j$Md1(rx3kGa}F$R{d_6teJO&ptu`_JdHy
z3(B#)iT37T7)vU^A47{Mi1FGRp*L2A(`$Vs`i_we4t6qz~r#k?`k(>X04+lFJ08vu#(W(YCH)mHYVgpgocO!67_p#^HG!0i&_l23p%H}
z2KLed>SL}2FWo^4s|zde92JrqvBNV(XHL1FrPE-1+zxre4c%~{CFGXIv?qWtQ#qrx
zu=idfEAB<$O-f5MZ7i>Pfj`igc{t?YL9>^_MjS#%Z{&>@9NKi){-6`id4@gEvkYtt
z>0sn?EcQ(pEY>i#TM8JzqoY4)=J(V=tKNz(fqlZ{c7y*`B)U_HO{s(}l}PEIqMr#g
zNWLJpb`jx!?R0=FV?VFAx9%cSgq)0+M(B2p23w&q24~G^4SEA%=*5li)%mEB^OHlco&COD2zp~p>ZOC{E%66bpoJ*h<5ie!Fb1-vfA
z&hh53ea;d;oKhr`C@^Eh$!cN6X_ZHG;`YarF*@3?(ez
zSZFL2-pU#;Q17DV5cJ#gKtS#rG>aY)xwD&KHXrtoh0;TiGz}(bi~bM_ZH6^;HPHbD
zJfw1`w{c7P!L+laHtuwe-P2vo@7>$*PAMD&=%&C^r>sT5N)x))piQ_qSQWVHatNxy
zDsXz0B_I>Jy3z61Eyg;a${q$w@{MzRPOM{W<#7by)X_2M%1C;KsOw51zoD1&GuF{8
zWKo>MBD21J!s4Z)V+b6Lp)L&}(I0Mxd?AILV0|vx>d&|tlXIP}`Y<>RffCBoOZf~_
z*g=ffoWa%P-j9+m<-P_#S{A2hGA_p^hn)e%
zDPzFR2a?*ZBnCl#SW;ZNDd0scIg*+j@|q#qEn~I2Cu-+MYj;i1QdaHuaazr-+N~9u
zr(Uy-(dN(6l9gJ|&DxMVwVBhjO1n1o7H!7u+NKfOo#VA_H)+!*YtwJjRtVa-k=n0j
mYxQ+nS)SHCN^{+pbSB~K0{mN7T@!Ez#9CZ9O9G)MRQ3N5H*4$w
literal 5278
zcmb_g33Qaz6@G7KvOj?ND$#5K^c}RVmq1q3BSw|XC{PHvHZiE
z-`0gg$6?Co0kK9w8<2rQK(@moOWXh>qDPStTmlg^*l3T+?Y-}x873|@_H=UY|Cay0
zd+)pV{x9EsmQKFfDy7`(^C&i_X8uI*A|XVVQtOoB>1FpQcHcys&!(}{LS&X&jTsgQ
z8Z0H%UZ2}(Ob!kSQxPpiHmlF0x+-}{@S)v{-EQX`)m84UDRH}e9=F4xc=UiSxY{X<
z+_|OJ(rRa!;+f?3IBh3OA9lolC6~Rl84hyKJ6X7K$)k7f%vfvSTi_mFlaxIrx+=GNnGd
z-Ht1J<4VP@I&BWa&f6R|yE5PHC|5irM{p|_yo5cC&ncP0GIy+X9@k8ZwB>)&v`^&o
zuvTi-CMvpE7cu{xKaH$)na^+*=UCIEofxMre^gsvr3cU;KAbklhv|%S9rdFxW-5z(
zlT^h~-b;wAQfu6ggM~;hwa!+R8tft048>dJc1g2>;)P%UZR?sEGei7Djbiwa-@O
zP$qahwpu1c2D(pnLy=7K69%ui+UIk-*oI&<;=h(L_Iv<;8t>bAWs`@SbGV^DSWlUJeKHRMZomxwq#SKlu
zEa?%7^b=`wM;F-VrK1JCkuC$fl~pr4Q&~B)v0Io2pDyexD2G?%2ySN$yn!`XC@)NE
zAtq@cxJ6`ny{bxTiZph(7x(M_B0xn~B|Q<(Rmudh2Oj~kD{>7gA2rrc-rZ0>85KF$
zLVWtr1Us{B%|T_P5SQpW`3_?+#c8WlC?vh5`|@xtxzBJ>-1Sz)hdxWguLL`xI!;;G
z1NW^u6qn7ZcyB9n+dSnn@uSrB+^HHb)7VMIj5gu?4Tj$n8p*kXU)2X)P$|b8Vjy0HtsiFcu0P3e7JdT`Q?Z)vz`meAZV#GtKXwTpreYqJwZ47*4P;5hg
z+Vq%fRO}0Q_w*%rFQujasSo~T
zyhon*@coIC7h%tyv*2`Y1e2-H!zjp-5cb6O_hEO_McDPmMcGpSN9j%EJN_x`KH35s
zx1E6j10F*=do4g&CX!eC>n=d~x>iZEmmh_zdi853i^epc;JM?;PvO=TXQ3c)0&**k
zBxMbG@FQ?+{2CT)Y)ewX9rr`GK0~EEYH6JMzI^Q^n6s({N**}{-7C@mak~nZU4ZI_
zZ^4^F_dM4O1+x}PS=7=v@!o@cuFc87yb>mMLvQ-wa1dOra#*X`bz-%k&csg5Wuw+VD{?sFl=#CQr6s!
zt+4DEz+=ZdPJd|xxNi?Y+1k%xj5tZMWKNXrY=ytQ10ALnZviYry-N=Ols|U~Ml9Oj
zhO%U?y7sri>h}QFobDK{J_WF%2_S$zsi?mMeP=Cu2W90WnHIg;3Yd2A+(#Xwb)NvN
zLfsF(25?v1Md&hkN*&6P-}awRw?gz1bckMP1z3Lp;HhS`>nOm$X$zZB&O{`6<~-Kg
z3OfLx0g2k5qBS3W_-*B?wVw~1H0Kaw{7#f}HIh6Fv0e8wXbti%N4giO1c~INp7}j-
z{J#+GD`5|I|Ifc1Zdl1#H{3s$7IU(ln`9sV%Va#j&GC6;=IQZ1+Qf6^e<7S@nY>4Q
z9#`^Is(U%lI`ZG6$u|oN;Ad?lqGcf7#zGVQgSm7H<(7A=bd4
zA!b0_D4`PmUzez7CgEhla){OlgeQhKZa{49&qFy988eoH8giI{ih}`yW&zO&kxoSg
zQemNrXl!!?p@|SVaWRNrs+}&Zm@)~S7Zu4u1EIH3VHmJ{w#`wkVDZC;hzMeu>};yd
zWW6LUnXK3l>JtXL=Cw_Ji$=ijb%d_{wsZtBZ|xihIcD6o0oeivnDoWco1TCEA6#$J
z1