From 1b2cc9ce34831958031d756e29a97b19928e0167 Mon Sep 17 00:00:00 2001 From: Uli Kusterer Date: Sat, 2 Aug 2003 00:23:50 +0200 Subject: [PATCH] Plugin registry, unique ID determining in "create" sheet, export of resources etc. --- Cocoa/Classes/ApplicationDelegate.m | 11 +- Cocoa/Classes/CreateResourceSheetController.m | 67 +++- Cocoa/Classes/InfoWindowController.h | 1 + Cocoa/Classes/InfoWindowController.m | 18 +- Cocoa/Classes/OpenFileDataSource.m | 16 +- Cocoa/Classes/PasteboardDocument.m | 12 +- Cocoa/Classes/RKEditorRegistry.h | 44 +++ Cocoa/Classes/RKEditorRegistry.m | 185 ++++++++++ Cocoa/Classes/Resource.h | 5 + Cocoa/Classes/Resource.m | 14 + Cocoa/Classes/ResourceDataSource.h | 8 +- Cocoa/Classes/ResourceDataSource.m | 97 ++++- Cocoa/Classes/ResourceDocument.h | 3 + Cocoa/Classes/ResourceDocument.m | 347 +++++++++++++++--- Cocoa/Plug-Ins/Hex Editor/HexEditorDelegate.m | 21 +- Cocoa/Plug-Ins/Hex Editor/HexTextView.m | 6 +- .../Plug-Ins/Hex Editor/HexWindowController.m | 5 - Cocoa/Plug-Ins/ResKnifePluginProtocol.h | 54 ++- Cocoa/Plug-Ins/ResKnifeResourceProtocol.h | 70 +++- .../TemplateWindowController.h | 2 +- .../TemplateWindowController.m | 4 +- Cocoa/Resources/Export.tiff | Bin 0 -> 17852 bytes Cocoa/main.m | 6 + NovaTools/Structs.h | 3 +- NovaTools/char/CharWindowController.m | 14 +- Prefix Files/C99 Prefix.h | 2 +- 26 files changed, 868 insertions(+), 147 deletions(-) create mode 100644 Cocoa/Classes/RKEditorRegistry.h create mode 100644 Cocoa/Classes/RKEditorRegistry.m create mode 100644 Cocoa/Resources/Export.tiff create mode 100644 Cocoa/main.m diff --git a/Cocoa/Classes/ApplicationDelegate.m b/Cocoa/Classes/ApplicationDelegate.m index edef246..f3cb672 100644 --- a/Cocoa/Classes/ApplicationDelegate.m +++ b/Cocoa/Classes/ApplicationDelegate.m @@ -27,6 +27,9 @@ - (void)awakeFromNib { + NSTableColumn *tableColumn; + NSButtonCell *buttonCell; + // Part of my EvilPlanª to find out how many people use ResKnife and how often! int launchCount = [[NSUserDefaults standardUserDefaults] integerForKey:@"LaunchCount"]; [[NSUserDefaults standardUserDefaults] setInteger:launchCount + 1 forKey:@"LaunchCount"]; @@ -38,8 +41,8 @@ [icons setObject:[[NSWorkspace sharedWorkspace] iconForFileType:@"icns"] forKey:@"icns"]; // set up open dialog's aux table view - NSTableColumn *tableColumn = [forkTableView tableColumnWithIdentifier:@"parse"]; - NSButtonCell *buttonCell = [[[NSButtonCell alloc] initTextCell:@""] autorelease]; + tableColumn = [forkTableView tableColumnWithIdentifier:@"parse"]; + buttonCell = [[[NSButtonCell alloc] initTextCell:@""] autorelease]; [buttonCell setEditable:YES]; [buttonCell setButtonType:NSSwitchButton]; [tableColumn setDataCell:buttonCell]; @@ -170,10 +173,10 @@ /* Don't tell anyone I did this... */ -- (void)setTreatsFilePackagesAsDirectories:(BOOL)flag +/*- (void)setTreatsFilePackagesAsDirectories:(BOOL)flag { #pragma unused( flag ) _spFlags.treatsFilePackagesAsDirectories = YES; -} +}*/ @end \ No newline at end of file diff --git a/Cocoa/Classes/CreateResourceSheetController.m b/Cocoa/Classes/CreateResourceSheetController.m index 1d137a1..ed7470d 100644 --- a/Cocoa/Classes/CreateResourceSheetController.m +++ b/Cocoa/Classes/CreateResourceSheetController.m @@ -5,32 +5,56 @@ @implementation CreateResourceSheetController -- (void)controlTextDidChange:(NSNotification *)notification -{ - BOOL enableButton = NO, clash = NO; - NSString *type = [typeView stringValue]; - NSNumber *resID = [NSNumber numberWithInt:[resIDView intValue]]; +/* ----------------------------------------------------------------------------- + controlTextDidChange: + Someone changed the control ID edit field. Check whether this is + a unique ID and appropriately enable the "create" button. + + Check "notification" against being nil, which is how we call it when + we need to explicitly update the enabled state of the "create" button. + - if( [type length] == 4 && [[resIDView stringValue] length] > 0 ) + REVISIONS: + 2003-08-01 UK Commented, changed to use data source's resourceOfType + instead of directly messing with the resource list's + enumerator Removed ID > 0 check -- negative IDs are + allowed as well. + -------------------------------------------------------------------------- */ + +-(void) controlTextDidChange: (NSNotification*)notification +{ + BOOL enableButton = NO; + NSString *type = [typeView stringValue]; + NSNumber *resID = [NSNumber numberWithInt:[resIDView intValue]]; + + if( [type length] == 4 ) { // I could use +[Resource getResourceOfType:andID:inDocument:] != nil, but that would be much slower - Resource *resource; - NSEnumerator *enumerator = [[[document dataSource] resources] objectEnumerator]; - while( resource = [enumerator nextObject] ) - { - if( [type isEqualToString:[resource type]] && [resID isEqualToNumber:[resource resID]] ) - clash = YES; - } - if( !clash ) enableButton = YES; + Resource *resource = [[document dataSource] resourceOfType:type andID:resID]; + if( resource == nil ) // No resource with that type and ID yet? + enableButton = YES; } [createButton setEnabled:enableButton]; } -- (void)showCreateResourceSheet:(ResourceDocument *)sheetDoc + +/* ----------------------------------------------------------------------------- + showCreateResourceSheet: + Show our sheet and set it up before that. + + REVISIONS: + 2003-08-01 UK Commented, made it "fake" a popup selection so + type field and popup match. Made it suggest an unused + resource ID. + -------------------------------------------------------------------------- */ + +-(void) showCreateResourceSheet: (ResourceDocument*)sheetDoc { // bug: didEndSelector could be better employed than using the button's targets from interface builder document = sheetDoc; [NSApp beginSheet:[self window] modalForWindow:[document mainWindow] modalDelegate:self didEndSelector:NULL contextInfo:nil]; + [resIDView setObjectValue: [[document dataSource] uniqueIDForType: [typeView stringValue]]]; + [self typePopupSelection: typePopup]; // Puts current popup value in text field and updates state of "create" button. } - (IBAction)hideCreateResourceSheet:(id)sender @@ -55,10 +79,21 @@ [NSApp endSheet:[self window]]; } -- (IBAction)typePopupSelection:(id)sender + +/* ----------------------------------------------------------------------------- + typePopupSelection: + Someone chose an item from our "res type" popup menu. Update our + edit field to show that. + + REVISIONS: + 2003-08-01 UK Commented, made it update state of "create" button.. + -------------------------------------------------------------------------- */ + +-(IBAction) typePopupSelection:(id)sender { [typeView setStringValue:[typePopup titleOfSelectedItem]]; [typeView selectText:sender]; + [self controlTextDidChange: nil]; // Make sure "create" button is updated. } @end diff --git a/Cocoa/Classes/InfoWindowController.h b/Cocoa/Classes/InfoWindowController.h index 8269322..772cf99 100644 --- a/Cocoa/Classes/InfoWindowController.h +++ b/Cocoa/Classes/InfoWindowController.h @@ -35,6 +35,7 @@ enum Attributes - (void)updateInfoWindow; - (void)setMainWindow:(NSWindow *)mainWindow; - (IBAction)attributesChanged:(id)sender; +- (IBAction)nameChanged: (id)sender; - (void)resourceAttributesDidChange:(NSNotification *)notification; - (void)documentInfoDidChange:(NSNotification *)notification; diff --git a/Cocoa/Classes/InfoWindowController.m b/Cocoa/Classes/InfoWindowController.m index d33cb76..b6560e2 100644 --- a/Cocoa/Classes/InfoWindowController.m +++ b/Cocoa/Classes/InfoWindowController.m @@ -40,8 +40,11 @@ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(documentInfoDidChange:) name:DocumentInfoDidChangeNotification object:nil]; } -- (void)updateInfoWindow +-(void) updateInfoWindow { + [nameView setEditable:(selectedResource != nil)]; + [nameView setDrawsBackground:(selectedResource != nil)]; + if( selectedResource ) { [[self window] setTitle:@"Resource Info"]; @@ -71,8 +74,8 @@ [[self window] setTitle:@"Document Info"]; [iconView setImage:[NSImage imageNamed:@"Resource file"]]; [nameView setStringValue:[currentDocument fileName]? [[currentDocument fileName] lastPathComponent]:[currentDocument displayName]]; - [[filePropertyForm cellAtIndex:0] setStringValue:@"hi:)"/*[currentDocument creator]*/]; - [[filePropertyForm cellAtIndex:1] setStringValue:@"helo"/*[currentDocument type]*/]; + [[filePropertyForm cellAtIndex:0] setStringValue:[currentDocument creator]]; + [[filePropertyForm cellAtIndex:1] setStringValue:[currentDocument type]]; // [[filePropertyForm cellAtIndex:2] setObjectValue:[NSNumber numberWithUnsignedLongLong:dataLogicalSize]]; // [[filePropertyForm cellAtIndex:3] setObjectValue:[NSNumber numberWithUnsignedLongLong:rsrcLogicalSize]]; [[filePropertyForm cellAtIndex:2] setStringValue:[[NSNumber numberWithUnsignedLongLong:dataLogicalSize] description]]; @@ -102,6 +105,8 @@ - (void)selectedResourceChanged:(NSNotification *)notification { + if( ![[nameView stringValue] isEqualToString: [selectedResource name]] ) + [self nameChanged:nameView]; selectedResource = [[notification object] selectedItem]; [self updateInfoWindow]; } @@ -119,8 +124,15 @@ [selectedResource setAttributes:[NSNumber numberWithShort:number]]; } +-(IBAction) nameChanged: (id)sender +{ + [selectedResource setName: [nameView stringValue]]; +} + - (void)resourceAttributesDidChange:(NSNotification *)notification; { + if( ![[nameView stringValue] isEqualToString: [selectedResource name]] ) + [self nameChanged:nameView]; [self updateInfoWindow]; } diff --git a/Cocoa/Classes/OpenFileDataSource.m b/Cocoa/Classes/OpenFileDataSource.m index 20008c2..0233a02 100644 --- a/Cocoa/Classes/OpenFileDataSource.m +++ b/Cocoa/Classes/OpenFileDataSource.m @@ -3,8 +3,8 @@ #import struct directoryinfo { -ÊÊ unsigned long length; -ÊÊ u_int32_t dirid; + unsigned long length; + u_int32_t dirid; }; struct dunnowhat @@ -25,8 +25,8 @@ struct dunnowhat /* NSTableView data source protocol implementation */ - (int)numberOfRowsInTableView:(NSTableView *)tableView { - NSBrowser *browser = [(NSOpenPanel *)[tableView window] browser]; - if( [[browser selectedCells] count] == 1 ) + //NSBrowser *browser = [(NSOpenPanel *)[tableView window] browser]; + //if( [[browser selectedCells] count] == 1 ) { // only one file is selected, parse it for forks /* const char *path = [[browser path] cString]; @@ -45,7 +45,7 @@ struct dunnowhat NSLog( @"%d", fileinfo.length ); NSLog( @"%d", fileinfo.dirid ); */ - struct attrlist alist; + /*struct attrlist alist; struct directoryinfo dirinfo; char *path = [[browser path] cString]; bzero(&alist, sizeof(alist)); @@ -54,11 +54,11 @@ struct dunnowhat int result = getattrlist(path, &alist, &dirinfo, sizeof(dirinfo), 0); printf("result: %d; directory id: %lu; %s\n", result, dirinfo.dirid, path); - return 3; + return 3;*/ } // multiple/no selected files, return nothing - else return 0; + /*else*/ return 0; } - (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row @@ -107,7 +107,7 @@ struct dunnowhat - (NSBrowser *)browser { - return _browser; + return nil; //return _browser; } @end \ No newline at end of file diff --git a/Cocoa/Classes/PasteboardDocument.m b/Cocoa/Classes/PasteboardDocument.m index dcabc6d..1d19278 100644 --- a/Cocoa/Classes/PasteboardDocument.m +++ b/Cocoa/Classes/PasteboardDocument.m @@ -26,15 +26,19 @@ // create the resource & add it to the array NSString *name = pbName; NSString *type; + NSNumber *resID; + NSNumber *attributes; + NSData *data; + Resource *resource; NS_DURING type = [currentType substringToIndex:3]; NS_HANDLER type = currentType; NS_ENDHANDLER - NSNumber *resID = [NSNumber numberWithShort:0]; - NSNumber *attributes = [NSNumber numberWithShort:0]; - NSData *data = [pb dataForType:type]; - Resource *resource = [Resource resourceOfType:type andID:resID withName:name andAttributes:attributes data:data]; + resID = [NSNumber numberWithShort:0]; + attributes = [NSNumber numberWithShort:0]; + data = [pb dataForType:type]; + resource = [Resource resourceOfType:type andID:resID withName:name andAttributes:attributes data:data]; [resources addObject:resource]; // array retains resource } [[self undoManager] enableUndoRegistration]; diff --git a/Cocoa/Classes/RKEditorRegistry.h b/Cocoa/Classes/RKEditorRegistry.h new file mode 100644 index 0000000..e0e0f4b --- /dev/null +++ b/Cocoa/Classes/RKEditorRegistry.h @@ -0,0 +1,44 @@ +/* ============================================================================= + PROJECT: ResKnife + FILE: RKEditorRegistry.h + + PURPOSE: + This is a registry where all our resource-editor plugins are looked + up and entered in a list, so you can ask for the editor for a specific + resource type and it is returned immediately. This registry reads the + types a plugin handles from their info.plist. This is better than + encoding the type in the plugin file name, as file names are not + guaranteed to be on a case-sensitive file system on Mac, and this also + allows an editor to register for several resource types. + + AUTHORS: M. Uli Kusterer, witness(at)zathras.de, (c) 2003. + + REVISIONS: + 2003-07-31 UK Created. + ========================================================================== */ + +/* ----------------------------------------------------------------------------- + Headers: + -------------------------------------------------------------------------- */ + +#import +#import "ResKnifePluginProtocol.h" +#import "ResKnifeResourceProtocol.h" + + +/* ----------------------------------------------------------------------------- + Class interface: + -------------------------------------------------------------------------- */ + +@interface RKEditorRegistry : NSObject +{ + NSMutableDictionary* typeRegistry; // Private. Use editorForType: to access this. +} + ++(RKEditorRegistry*) mainRegistry; // There's usually only one object, and this returns or creates it. + +-(IBAction) scanForPlugins: (id)sender; // Called automatically by mainRegistry. +-(Class) editorForType: (NSString*)typeStr; // You probably want to call this. + + +@end diff --git a/Cocoa/Classes/RKEditorRegistry.m b/Cocoa/Classes/RKEditorRegistry.m new file mode 100644 index 0000000..e147582 --- /dev/null +++ b/Cocoa/Classes/RKEditorRegistry.m @@ -0,0 +1,185 @@ +/* ============================================================================= + PROJECT: ResKnife + FILE: RKEditorRegistry.m + + PURPOSE: + This is a registry where all our resource-editor plugins are looked + up and entered in a list, so you can ask for the editor for a specific + resource type and it is returned immediately. This registry reads the + types a plugin handles from their info.plist. This is better than + encoding the type in the plugin file name, as file names are not + guaranteed to be on a case-sensitive file system on Mac, and this also + allows an editor to register for several resource types. + + AUTHORS: M. Uli Kusterer, witness(at)zathras.de, (c) 2003. + + REVISIONS: + 2003-07-31 UK Created. + ========================================================================== */ + +/* ----------------------------------------------------------------------------- + Headers: + -------------------------------------------------------------------------- */ + +#import "RKEditorRegistry.h" + + +/* ----------------------------------------------------------------------------- + Globals: + -------------------------------------------------------------------------- */ + +RKEditorRegistry* gRKEditorRegistryMainRegistry = nil; // Access through +mainRegistry! + + +@implementation RKEditorRegistry + +/* ----------------------------------------------------------------------------- + mainRegistry: + Returns the main plugin registry of this application, instantiating + it first if there is none yet. As soon as this is instantiated, the + plugins are loaded. + + REVISIONS: + 2003-07-31 UK Created. + -------------------------------------------------------------------------- */ + ++(RKEditorRegistry*) mainRegistry +{ + if( !gRKEditorRegistryMainRegistry ) + { + gRKEditorRegistryMainRegistry = [[RKEditorRegistry alloc] init]; + [gRKEditorRegistryMainRegistry scanForPlugins: gRKEditorRegistryMainRegistry]; + } + return gRKEditorRegistryMainRegistry; +} + + +/* ----------------------------------------------------------------------------- + awakeFromNib: + Makes sure that if an instance of this is instantiated from a NIB file, + it automatically loads the plugins. + + REVISIONS: + 2003-07-31 UK Created. + -------------------------------------------------------------------------- */ + +-(void) awakeFromNib +{ + [self scanForPlugins: self]; +} + + +/* ----------------------------------------------------------------------------- + scanForPlugins: + (Re)loads our list of plugins. You can use this as an action for a menu + item, if you want. + + This scans the application's internal Plugins folder, + ~/Library/Application Support/ResKnife/Plugins/ and + /Library/Application Support/ResKnife/Plugins/ for plugins that have + the extension ".plugin" and implement initWithResource: (which means + this won't get into the way if you want to support other kinds of + plugins). + + It builds a registry of Class objects in an NSMutableDictionary, where + the key is the resource type. If a plugin supports several resource + types (as indicated by the RKEditedTypes key in its Info.plist), it + will be registered for these types as well. If several plugins register + for the same type, the last one loaded wins. + + To instantiate an object from a plugin, see the method below. + + TODO: + Currently, Cocoa classes can't be unloaded, which means we're not + leaking the NSBundles we load here. However, if this one day shouldn't + hold true anymore, we'll want to retain these bundles in our dictionary + and do the principalClass thingie in editorForType: instead, which + allows us to get rid of the class and its bundle when reloading the + plugin list by simply relying on NSMutableDictionary to release it. + + REVISIONS: + 2003-07-31 UK Created. + -------------------------------------------------------------------------- */ + +-(IBAction) scanForPlugins: (id)sender +{ + // TODO: Instead of hard-coding sysPath we should use some FindFolder-like API! + Class pluginClass; + NSString *appSupport = @"Library/Application Support/ResKnife/Plugins/"; + NSString *appPath = [[NSBundle mainBundle] builtInPlugInsPath]; + NSString *userPath = [NSHomeDirectory() stringByAppendingPathComponent:appSupport]; + NSString *sysPath = [@"/" stringByAppendingPathComponent:appSupport]; + NSArray *paths = [NSArray arrayWithObjects:appPath, userPath, sysPath, nil]; + NSEnumerator *pathEnum = [paths objectEnumerator]; + NSString *path; + + if( typeRegistry ) + [typeRegistry release]; + typeRegistry = [[NSMutableDictionary alloc] init]; + + while( path = [pathEnum nextObject] ) + { + NSEnumerator *e = [[[NSFileManager defaultManager] directoryContentsAtPath:path] objectEnumerator]; + NSString *name; + + NSLog(@"Looking for plugins at %@", path); + + while( name = [e nextObject] ) + { + name = [path stringByAppendingPathComponent:name]; + NSLog(@"Examining %@", name); + if( [[name pathExtension] isEqualToString:@"plugin"] ) + { + NSBundle *plugin = [NSBundle bundleWithPath: name]; + + NSLog(@"Identifier %@", [plugin bundleIdentifier]); + if( pluginClass = [plugin principalClass] ) + { + NSLog(@"Found plugin: %@", name); + if( [pluginClass instancesRespondToSelector:@selector(initWithResource:)] ) + { + NSString *resType; + NSArray *types = [[plugin infoDictionary] objectForKey:@"RKEditedTypes"]; + NSEnumerator *enny; + + if( types == nil ) + types = [NSArray arrayWithObject: [[plugin infoDictionary] objectForKey:@"RKEditedType"]]; + + for( enny = [types objectEnumerator]; resType = [enny nextObject]; ) + { + [typeRegistry setObject:pluginClass forKey:resType]; + NSLog(@"Registered for type %@.",resType); + } + } + } + } + } + } +} + + +/* ----------------------------------------------------------------------------- + editorForType: + Looks up the editor for the specified type in our registry of plugins + and returns the main class "object" that registered for this type, or + Nil if there is none registered for this type. + + Note that the resource type is stored as an NSString, which means it + can be longer than four characters (Currently used for looking up the + Hexadecimal and Template editors, which are special in that they work + with any resource). + + REVISIONS: + 2003-07-31 UK Created. + -------------------------------------------------------------------------- */ + +-(Class) editorForType: (NSString*)typeStr +{ + Class theClass = [typeRegistry objectForKey: typeStr]; + if( !theClass ) + return Nil; + + return theClass; +} + +@end diff --git a/Cocoa/Classes/Resource.h b/Cocoa/Classes/Resource.h index bf0909a..df7f9f7 100644 --- a/Cocoa/Classes/Resource.h +++ b/Cocoa/Classes/Resource.h @@ -16,6 +16,8 @@ // the actual data NSData *data; + + NSDocument *document; // Our owner. } // accessor methods not part of the protocol @@ -33,4 +35,7 @@ + (id)resourceOfType:(NSString *)typeValue andID:(NSNumber *)resIDValue withName:(NSString *)nameValue andAttributes:(NSNumber *)attributesValue; + (id)resourceOfType:(NSString *)typeValue andID:(NSNumber *)resIDValue withName:(NSString *)nameValue andAttributes:(NSNumber *)attributesValue data:(NSData *)dataValue; +-(void) setDocument: (NSDocument*)doc; +-(NSDocument*) document; // Resource protocol guarantees this. + @end diff --git a/Cocoa/Classes/Resource.m b/Cocoa/Classes/Resource.m index 6c0645a..935d38f 100644 --- a/Cocoa/Classes/Resource.m +++ b/Cocoa/Classes/Resource.m @@ -39,6 +39,7 @@ NSString *RKResourcePboardType = @"RKResourcePboardType"; return self; } + + (id)resourceOfType:(NSString *)typeValue andID:(NSNumber *)resIDValue { Resource *resource = [[Resource allocWithZone:[self zone]] initWithType:typeValue andID:resIDValue]; @@ -156,6 +157,19 @@ NSString *RKResourcePboardType = @"RKResourcePboardType"; [[NSNotificationCenter defaultCenter] postNotificationName:ResourceDidChangeNotification object:self]; } + +-(void) setDocument: (NSDocument*)doc +{ + document = doc; // It owns us, so don't retain, or we could get a closed loop! +} + + +-(NSDocument*) document +{ + return document; +} + + - (NSString *)representedFork { return representedFork; diff --git a/Cocoa/Classes/ResourceDataSource.h b/Cocoa/Classes/ResourceDataSource.h index 888cfe3..37c3abe 100644 --- a/Cocoa/Classes/ResourceDataSource.h +++ b/Cocoa/Classes/ResourceDataSource.h @@ -19,8 +19,10 @@ - (NSNumber *)uniqueIDForType:(NSString *)type; // accessors -- (Resource *)resourceOfType:(NSString *)type andID:(NSNumber *)resID; -- (Resource *)resourceOfType:(NSString *)type withName:(NSString *)name; -- (NSArray *)allResourcesOfType:(NSString *)type; +-(Resource*) resourceOfType: (NSString*)type andID: (NSNumber*)resID; +-(Resource*) resourceOfType: (NSString*)type withName: (NSString*)name; +-(NSArray*) allResourcesOfType: (NSString*)type; +-(NSArray*) allResourceIDsOfType: (NSString*)type; + @end diff --git a/Cocoa/Classes/ResourceDataSource.m b/Cocoa/Classes/ResourceDataSource.m index 4e29ae3..6f3b918 100644 --- a/Cocoa/Classes/ResourceDataSource.m +++ b/Cocoa/Classes/ResourceDataSource.m @@ -1,6 +1,32 @@ +/* ============================================================================= + PROJECT: ResKnife + FILE: ResourceDataSource.m + + PURPOSE: + Dedicated data source for our resource list. Shares its list of + resources with ResourceDocument. I have no idea why Nick did this + split, though... + + AUTHORS: Nick Shanks, nick(at)nickshanks.com, (c) ~2001. + M. Uli Kusterer, witness(at)zathras.de, (c) 2003. + + REVISIONS: + 2003-07-31 UK Added storing document pointer in resource, commented. + ========================================================================== */ + +/* ----------------------------------------------------------------------------- + Headers: + -------------------------------------------------------------------------- */ + #import "ResourceDataSource.h" #import "ResourceDocument.h" #import "Resource.h" +#import + + +/* ----------------------------------------------------------------------------- + Notification names: + -------------------------------------------------------------------------- */ NSString *DataSourceWillAddResourceNotification = @"DataSourceWillAddResourceNotification"; NSString *DataSourceDidAddResourceNotification = @"DataSourceDidAddResourceNotification"; @@ -46,6 +72,7 @@ NSString *DataSourceDidRemoveResourceNotification = @"DataSourceDidRemoveResourc // 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 hundereds of times upon load + [resource setDocument:document]; [resources addObject:resource]; [outlineView reloadData]; @@ -66,17 +93,21 @@ NSString *DataSourceDidRemoveResourceNotification = @"DataSourceDidRemoveResourc [[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 + +/* ----------------------------------------------------------------------------- + resourceDidChange: + Notification from the Resource class that we're registered to. It's + sent whenever the resource is "touch"ed. + + REVISIONS: + 2003-08-01 UK Commented, made this "touch" the document as well. + -------------------------------------------------------------------------- */ + +-(void) resourceDidChange: (NSNotification*)notification { // reload the data for the changed resource [outlineView reloadItem:[notification object]]; -} - -- (NSNumber *)uniqueIDForType:(NSString *)type -{ - short resID = 128; - while( [self resourceOfType:type andID:[NSNumber numberWithShort:resID]] != nil ) resID++; - return [NSNumber numberWithShort:resID]; + [document updateChangeCount: NSChangeDone]; // TODO: We shouldn't need to do this, Undo should take care of this, according to the docs, but somehow the document always forgets its changes. } /* Data source protocol implementation */ @@ -153,4 +184,54 @@ NSString *DataSourceDidRemoveResourceNotification = @"DataSourceDidRemoveResourc return [NSArray arrayWithArray:array]; } + +/* ----------------------------------------------------------------------------- + allResourceIDsOfType: + Returns an NSArray full of NSNumber* objects containing the IDs of all + resources of specified type. Used by uniqueIDForType:. + + REVISIONS: + 2003-08-01 UK Created based on allResourcesOfType:. + -------------------------------------------------------------------------- */ + +-(NSArray*) allResourceIDsOfType: (NSString*)type +{ + 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]; +} + + +/* ----------------------------------------------------------------------------- + uniqueIDForType: + 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. + + REVISIONS: + 2003-08-01 UK Created. + -------------------------------------------------------------------------- */ + +-(NSNumber*) uniqueIDForType: (NSString*)type +{ + short theID = 128; + NSArray *array = [self allResourceIDsOfType: type]; + + if( [array count] <= USHRT_MAX ) + { + while( [array containsObject: [NSNumber numberWithShort:theID]] ) + theID++; + } + + return [NSNumber numberWithShort: theID]; +} + @end diff --git a/Cocoa/Classes/ResourceDocument.h b/Cocoa/Classes/ResourceDocument.h index 283a077..0dcceb4 100644 --- a/Cocoa/Classes/ResourceDocument.h +++ b/Cocoa/Classes/ResourceDocument.h @@ -29,6 +29,9 @@ - (IBAction)playSound:(id)sender; - (void)sound:(NSSound *)sound didFinishPlaying:(BOOL)finished; +-(IBAction) exportResourceToFile: (id)sender; +-(IBAction) exportResourceToImageFile: (id)sender; + - (IBAction)copy:(id)sender; - (IBAction)paste:(id)sender; - (void)pasteResources:(NSArray *)pastedResources; diff --git a/Cocoa/Classes/ResourceDocument.m b/Cocoa/Classes/ResourceDocument.m index 4142e61..f7c8b9e 100644 --- a/Cocoa/Classes/ResourceDocument.m +++ b/Cocoa/Classes/ResourceDocument.m @@ -1,3 +1,25 @@ +/* ============================================================================= + PROJECT: ResKnife + FILE: ResourceDocument.m + + PURPOSE: + This is a ResKnife document (I still write Resurrection occasionally, + sorry Nick...), it handles loading, display etc. of resources. + + It uses a separate object as the data source for its outline view, + though, ResourceDataSource. I'd better ask Nick why. + + AUTHORS: Nick Shanks, nick(at)nickshanks.com, (c) ~2001. + M. Uli Kusterer, witness(at)zathras.de, (c) 2003. + + REVISIONS: + 2003-07-31 UK Added support for plugin registry, commented. + ========================================================================== */ + +/* ----------------------------------------------------------------------------- + Headers: + -------------------------------------------------------------------------- */ + #import "ResourceDocument.h" #import "ResourceDataSource.h" #import "ResourceNameCell.h" @@ -8,10 +30,17 @@ #import "NSOutlineView-SelectedItems.h" #import "ResKnifePluginProtocol.h" +#import "RKEditorRegistry.h" + + +/* ----------------------------------------------------------------------------- + Notification names: + -------------------------------------------------------------------------- */ NSString *DocumentInfoWillChangeNotification = @"DocumentInfoWillChangeNotification"; NSString *DocumentInfoDidChangeNotification = @"DocumentInfoDidChangeNotification"; + extern NSString *RKResourcePboardType; @implementation ResourceDocument @@ -19,9 +48,13 @@ extern NSString *RKResourcePboardType; - (id)init { self = [super init]; + if( !self ) + return nil; toolbarItems = [[NSMutableDictionary alloc] init]; resources = [[NSMutableArray alloc] init]; fork = nil; + creator = [@"ResK" retain]; + type = [@"rsrc" retain]; return self; } @@ -31,6 +64,8 @@ extern NSString *RKResourcePboardType; if( fork ) DisposePtr( (Ptr) fork ); [resources release]; [toolbarItems release]; + [type release]; + [creator release]; [super dealloc]; } @@ -111,6 +146,16 @@ extern NSString *RKResourcePboardType; 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:) ) + { + Class edClass; + + if( selectedRows < 1 ) + return NO; + + edClass = [[RKEditorRegistry mainRegistry] editorForType: [resource type]]; + return [edClass 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]; @@ -126,6 +171,7 @@ 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.ulikusterer.resknife.toolbar.export"; - (void)setupToolbar:(NSWindowController *)windowController { @@ -135,6 +181,7 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh [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)]; @@ -142,9 +189,9 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh [item setTarget:self]; [item setAction:@selector(showCreateResourceSheet:)]; [toolbarItems setObject:item forKey:RKCreateItemIdentifier]; - [item release]; item = [[NSToolbarItem alloc] initWithItemIdentifier:RKDeleteItemIdentifier]; + [item autorelease]; [item setLabel:NSLocalizedString(@"Delete", nil)]; [item setPaletteLabel:NSLocalizedString(@"Delete", nil)]; [item setToolTip:NSLocalizedString(@"Delete Selected Resource", nil)]; @@ -152,9 +199,9 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh [item setTarget:self]; [item setAction:@selector(clear:)]; [toolbarItems setObject:item forKey:RKDeleteItemIdentifier]; - [item release]; 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)]; @@ -162,9 +209,9 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh [item setTarget:self]; [item setAction:@selector(openResources:)]; [toolbarItems setObject:item forKey:RKEditItemIdentifier]; - [item release]; 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)]; @@ -172,9 +219,9 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh [item setTarget:self]; [item setAction:@selector(openResourcesAsHex:)]; [toolbarItems setObject:item forKey:RKEditHexItemIdentifier]; - [item release]; 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)]]; @@ -182,9 +229,9 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh [item setTarget:self]; [item setAction:@selector(saveDocument:)]; [toolbarItems setObject:item forKey:RKSaveItemIdentifier]; - [item release]; 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)]; @@ -192,14 +239,23 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh [item setTarget:[NSApp delegate]]; [item setAction:@selector(showInfo:)]; [toolbarItems setObject:item forKey:RKShowInfoItemIdentifier]; - [item release]; + + 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(exportResourceToFile:)]; + [toolbarItems setObject:item forKey:RKExportItemIdentifier]; if( [windowController window] == mainWindow ) { NSToolbar *toolbar = [[[NSToolbar alloc] initWithIdentifier:RKToolbarIdentifier] autorelease]; // set toolbar properties - [toolbar setVisible:NO]; + [toolbar setVisible:YES]; [toolbar setAutosavesConfiguration:YES]; [toolbar setAllowsUserCustomization:YES]; [toolbar setDisplayMode:NSToolbarDisplayModeDefault]; @@ -217,12 +273,12 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh - (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar { - return [NSArray arrayWithObjects:RKCreateItemIdentifier, RKEditItemIdentifier, RKEditHexItemIdentifier, NSToolbarSeparatorItemIdentifier, RKSaveItemIdentifier, NSToolbarPrintItemIdentifier, NSToolbarFlexibleSpaceItemIdentifier, NSToolbarCustomizeToolbarItemIdentifier, nil]; + 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, RKShowInfoItemIdentifier, NSToolbarPrintItemIdentifier, NSToolbarCustomizeToolbarItemIdentifier, NSToolbarFlexibleSpaceItemIdentifier, NSToolbarSpaceItemIdentifier, NSToolbarSeparatorItemIdentifier, nil]; + return [NSArray arrayWithObjects:RKCreateItemIdentifier, RKDeleteItemIdentifier, RKEditItemIdentifier, RKEditHexItemIdentifier, RKSaveItemIdentifier, RKExportItemIdentifier, RKShowInfoItemIdentifier, NSToolbarPrintItemIdentifier, NSToolbarCustomizeToolbarItemIdentifier, NSToolbarFlexibleSpaceItemIdentifier, NSToolbarSpaceItemIdentifier, NSToolbarSeparatorItemIdentifier, nil]; } - (BOOL)validateToolbarItem:(NSToolbarItem *)item @@ -235,6 +291,7 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh 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; @@ -286,18 +343,29 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh [self openResourceAsHex:resource]; } -- (void)openResourceUsingEditor:(Resource *)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. + -------------------------------------------------------------------------- */ + +-(void) openResourceUsingEditor: (Resource*)resource { -// #warning openResourceUsingEditor: shortcuts to NovaTools !! - // opens resource in template using TMPL resource with name templateName -// NSBundle *editor = [NSBundle bundleWithPath:[[[NSBundle mainBundle] builtInPlugInsPath] stringByAppendingPathComponent:@"NovaTools.plugin"]]; - NSBundle *editor = [NSBundle bundleWithPath:[[[NSBundle mainBundle] builtInPlugInsPath] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@ Editor.plugin", [resource type]]]]; + Class editorClass = [[RKEditorRegistry mainRegistry] editorForType: [resource type]]; // open the resources, passing in the template to use - if( editor /*&& [[editor principalClass] respondsToSelector:@selector(initWithResource:)]*/ ) + 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? - id plug = [(id )[[editor principalClass] alloc] initWithResource:resource]; + // update: doug says window controllers automatically release themselves when their window is closed. + id plug = [(id )[editorClass alloc] initWithResource:resource]; if( plug ) return; } @@ -305,21 +373,34 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh [self openResource:resource usingTemplate:[resource type]]; } -- (void)openResource:(Resource *)resource usingTemplate:(NSString *)templateName + +/* ----------------------------------------------------------------------------- + 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 - NSBundle *templateEditor = [NSBundle bundleWithPath:[[[NSBundle mainBundle] builtInPlugInsPath] stringByAppendingPathComponent:@"Template Editor.plugin"]]; + Class editorClass = [[RKEditorRegistry mainRegistry] editorForType: @"Template Editor"]; - // bug: this checks EVERY DOCUMENT for template resources (might not be desired) - // bug: it doesn't, however, check the application's resource map for a matching template! + // 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 /*&& [[templateEditor principalClass] respondsToSelector:@selector(initWithResources:)]*/ ) + if( tmpl && 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. - NSWindowController *plugController = [(id )[[templateEditor principalClass] alloc] initWithResources:resource, tmpl, nil]; + NSWindowController *plugController = [(id )[editorClass alloc] initWithResources:resource, tmpl, nil]; if( plugController ) return; } @@ -327,13 +408,30 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh [self openResourceAsHex:resource]; } -- (void)openResourceAsHex:(Resource *)resource + +/* ----------------------------------------------------------------------------- + openResourceAsHex: + 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. + + REVISIONS: + 2003-07-31 UK Changed to use plugin registry instead of file name. + -------------------------------------------------------------------------- */ + +-(void) openResourceAsHex: (Resource*)resource { - NSBundle *hexEditor = [NSBundle bundleWithPath:[[[NSBundle mainBundle] builtInPlugInsPath] stringByAppendingPathComponent:@"Hexadecimal Editor.plugin"]]; + Class editorClass = [[RKEditorRegistry mainRegistry] 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? - NSWindowController *plugController = [(id )[[hexEditor principalClass] alloc] initWithResource:resource]; + // update: doug says window controllers automatically release themselves when their window is closed. + NSWindowController *plugController = [(id )[editorClass alloc] initWithResource:resource]; } + +// TODO: These two 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. - (IBAction)playSound:(id)sender { // bug: can only cope with one selected item @@ -500,7 +598,7 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh if( [outlineView numberOfSelectedRows] > 1 ) [[self undoManager] setActionName:NSLocalizedString(@"Delete Resources", nil)]; - // deselct resources (otherwise other resources move into selected rows!) + // deselect resources (otherwise other resources move into selected rows!) [outlineView deselectAll:self]; } @@ -513,18 +611,39 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh return YES; }*/ -- (BOOL)readFromFile:(NSString *)fileName ofType:(NSString *)type + +/* ----------------------------------------------------------------------------- + readFromFile:ofType: + 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. + + REVISIONS: + 2003-08-01 UK Commented. + -------------------------------------------------------------------------- */ + +-(BOOL) readFromFile: (NSString*)fileName ofType: (NSString*)fileKind { - BOOL succeeded = NO; - OSStatus error = noErr; - HFSUniStr255 *resourceForkName = (HFSUniStr255 *) NewPtrClear( sizeof(HFSUniStr255) ); - FSRef *fileRef = (FSRef *) NewPtrClear( sizeof(FSRef) ); - SInt16 fileRefNum = 0; + BOOL succeeded = NO; + OSStatus error = noErr; + HFSUniStr255 *resourceForkName = (HFSUniStr255 *) NewPtrClear( sizeof(HFSUniStr255) ); // This may be saved away in the instance variable "fork" to keep track of which fork our resources are in. + FSRef *fileRef = (FSRef *) NewPtrClear( sizeof(FSRef) ); + SInt16 fileRefNum = 0; + FSCatalogInfo info = { 0 }; // open fork with resources in it error = FSPathMakeRef( [fileName cString], fileRef, nil ); error = FSGetResourceForkName( resourceForkName ); SetResLoad( false ); // don't load "preload" resources + + [type release]; + [creator release]; + + error = FSGetCatalogInfo( fileRef, kFSCatInfoFinderInfo, &info, nil, nil, nil ); + type = [[NSString stringWithCString: &((FileInfo*)info.finderInfo)->fileType length:4] retain]; + creator = [[NSString stringWithCString: &((FileInfo*)info.finderInfo)->fileCreator length:4] retain]; + + // Try res fork first: error = FSOpenResourceFile( fileRef, resourceForkName->length, (UniChar *) &resourceForkName->unicode, fsRdPerm, &fileRefNum); if( error ) // try to open data fork instead { @@ -540,7 +659,7 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh // read the resources (without spawning thousands of undos for resource creation) [[self undoManager] disableUndoRegistration]; - if( fileRefNum && !error ) + if( fileRefNum && error == noErr ) succeeded = [self readResourceMap:fileRefNum]; else if( !fileRefNum ) { @@ -551,7 +670,7 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh [[self undoManager] enableUndoRegistration]; // tidy up loose ends - if( !fork ) DisposePtr( (Ptr) resourceForkName ); // only delete if we're not saving it + if( !fork ) DisposePtr( (Ptr) resourceForkName ); // only delete if we're not saving it to "fork" instance var. if( fileRefNum ) FSClose( fileRefNum ); DisposePtr( (Ptr) fileRef ); return succeeded; @@ -570,31 +689,41 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh It is perfectly legal in ResKnife to read in forks of these names when accessing a shared NTFS drive from a server running SFM. */ [resource setRepresentedFork:forkName]; + [resource setDocument:self]; [resources insertObject:resource atIndex:0]; return YES; } else return NO; } -- (BOOL)readResourceMap:(SInt16)fileRefNum +-(BOOL) readResourceMap: (SInt16)fileRefNum { OSStatus error = noErr; unsigned short n; + unsigned short i; SInt16 oldResFile = CurResFile(); UseResFile( fileRefNum ); - for( unsigned short i = 1; i <= Count1Types(); i++ ) + for( i = 1; i <= Count1Types(); i++ ) { ResType resType; + unsigned short j; + Get1IndType( &resType, i ); n = Count1Resources( resType ); - for( unsigned short j = 1; j <= n; j++ ) + for( j = 1; j <= n; j++ ) { - Str255 nameStr; - long sizeLong; - short resIDShort; - short attrsShort; - Handle resourceHandle; + Str255 nameStr; + long sizeLong; + short resIDShort; + short attrsShort; + Handle resourceHandle; + NSString *name; + NSString *type; + NSNumber *resID; + NSNumber *attributes; + NSData *data; + Resource *resource; resourceHandle = Get1IndResource( resType, j ); error = ResError(); @@ -611,12 +740,13 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh HLockHi( resourceHandle ); // create the resource & add it to the array - NSString *name = [NSString stringWithCString:&nameStr[1] length:nameStr[0]]; - NSString *type = [NSString stringWithCString:(char *) &resType length:4]; - 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]; + name = [NSString stringWithCString:&nameStr[1] length:nameStr[0]]; + type = [NSString stringWithCString:(char *) &resType length:4]; + resID = [NSNumber numberWithShort:resIDShort]; + attributes = [NSNumber numberWithShort:attrsShort]; + data = [NSData dataWithBytes:*resourceHandle length:sizeLong]; + resource = [Resource resourceOfType:type andID:resID withName:name andAttributes:attributes data:data]; + [resource setDocument:self]; [resources addObject:resource]; // array retains resource HUnlock( resourceHandle ); @@ -678,33 +808,57 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh return succeeded; } -- (BOOL)writeResourceMap:(SInt16)fileRefNum + +/* ----------------------------------------------------------------------------- + writeResourceMap: + Writes all resources (except the ones representing other forks of the + file) to the specified resource file. + + REVISIONS: + 2003-08-01 UK Swiss national holiday, and I'm stuck in Germany... + Commented, changed to use enumerator instead of + objectAtIndex. + -------------------------------------------------------------------------- */ + +-(BOOL) writeResourceMap: (SInt16)fileRefNum { - OSStatus error = noErr; - unsigned long i; - SInt16 oldResFile = CurResFile(); + OSStatus error = noErr; + NSEnumerator* enny; + Resource *resource; + + // Make the resource file current: + SInt16 oldResFile = CurResFile(); UseResFile( fileRefNum ); - for( i = 0; i < [resources count]; i++ ) + // Loop over all our resources: + for( enny = [resources objectEnumerator]; resource = [enny nextObject]; ) { - Resource *resource = [resources objectAtIndex:i]; - if( [resource representedFork] != nil ) continue; - Str255 nameStr; ResType resType; - short resIDShort = [[resource resID] shortValue]; - short attrsShort = [[resource attributes] shortValue]; - Handle resourceHandle = NewHandleClear( [[resource data] length] ); + short resIDShort; + short attrsShort; + Handle resourceHandle; + + // 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] ); + + // Unicode name -> P-String: nameStr[0] = [[resource name] cStringLength]; BlockMoveData( [[resource name] cString], &nameStr[1], nameStr[0] ); + // Type string to ResType: [[resource type] getCString:(char *) &resType maxLength:4]; + // NSData to resource data Handle: HLockHi( resourceHandle ); [[resource data] getBytes:*resourceHandle]; HUnlock( resourceHandle ); + // Now that everything's converted, write it to our file: AddResource( resourceHandle, resType, resIDShort, nameStr ); if( ResError() == addResFailed ) { @@ -720,7 +874,7 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh } } - // save resource map and clean up + // Save resource map and clean up: UseResFile( oldResFile ); return error? NO:YES; } @@ -807,4 +961,77 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh [[self undoManager] setActionName:NSLocalizedString( @"Change Creator & Type", nil)]; } + +-(void) exportDataPanelDidEnd:(NSSavePanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo +{ + NSData* data = contextInfo; + [data autorelease]; + + if( returnCode == NSOKButton ) + [data writeToFile:[sheet filename] atomically: YES]; +} + + +-(void) exportImagePanelDidEnd:(NSSavePanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo +{ + NSImage* img = contextInfo; + [img autorelease]; + + if( returnCode == NSOKButton ) + { + NSData* data = [img TIFFRepresentation]; + [data writeToFile:[sheet filename] atomically: YES]; + } +} + + +-(IBAction) exportResourceToFile: (id)sender +{ + Resource* resource = (Resource*) [outlineView selectedItem]; + NSData* theData; + Class edClass = [[RKEditorRegistry mainRegistry] editorForType: [resource type]]; + NSString* extension = [resource type]; + NSSavePanel* panel; + NSString* fName; + + if( [edClass respondsToSelector:@selector(dataForFileExport:)] ) + theData = [edClass dataForFileExport: resource]; + else + theData = [resource data]; + + if( [edClass respondsToSelector:@selector(extensionForFileExport:)] ) + extension = [edClass extensionForFileExport]; + + panel = [NSSavePanel savePanel]; + fName = [[resource name] stringByAppendingFormat: @".%@", extension]; + + [panel beginSheetForDirectory:nil file:fName modalForWindow:mainWindow modalDelegate:self + didEndSelector:@selector(exportDataPanelDidEnd:returnCode:contextInfo:) contextInfo:[theData retain]]; +} + + +-(IBAction) exportResourceToImageFile: (id)sender +{ + Resource* resource = (Resource*) [outlineView selectedItem]; + NSImage* theData; + Class edClass = [[RKEditorRegistry mainRegistry] editorForType: [resource type]]; + NSString* extension = @"tiff"; + NSSavePanel* panel; + NSString* fName; + + if( ![edClass respondsToSelector:@selector(imageForImageFileExport:)] ) + return; + + theData = [edClass imageForImageFileExport: resource]; + + if( [edClass respondsToSelector:@selector(extensionForImageFileExport:)] ) + extension = [edClass extensionForFileExport]; + + panel = [NSSavePanel savePanel]; + fName = [[resource name] stringByAppendingFormat: @".%@", extension]; + + [panel beginSheetForDirectory:nil file:fName modalForWindow:mainWindow modalDelegate:self + didEndSelector:@selector(exportImagePanelDidEnd:returnCode:contextInfo:) contextInfo:[theData retain]]; +} + @end diff --git a/Cocoa/Plug-Ins/Hex Editor/HexEditorDelegate.m b/Cocoa/Plug-Ins/Hex Editor/HexEditorDelegate.m index 42f31cd..7931cc8 100644 --- a/Cocoa/Plug-Ins/Hex Editor/HexEditorDelegate.m +++ b/Cocoa/Plug-Ins/Hex Editor/HexEditorDelegate.m @@ -21,8 +21,9 @@ int dataLength = [data length], bytesPerRow = [controller bytesPerRow]; int rows = (dataLength / bytesPerRow) + ((dataLength % bytesPerRow)? 1:0); NSMutableString *representation = [NSMutableString string]; + int row; - for( int row = 0; row < rows; row++ ) + for( row = 0; row < rows; row++ ) [representation appendFormat:@"%08lX:", row * bytesPerRow]; return representation; @@ -35,11 +36,14 @@ char buffer[bytesPerRow*3 +1], hex1, hex2; char *bytes = (char *) [data bytes]; NSMutableString *representation = [NSMutableString string]; + int row; // calculate bytes - for( int row = 0; row < rows; row++ ) + for( row = 0; row < rows; row++ ) { - for( int addr = 0; addr < bytesPerRow; addr++ ) + int addr; + + for( addr = 0; addr < bytesPerRow; addr++ ) { if( currentByte < dataLength ) { @@ -82,11 +86,14 @@ char buffer[bytesPerRow +1]; char *bytes = (char *) [data bytes]; NSMutableString *representation = [NSMutableString string]; + int row; // calculate bytes - for( int row = 0; row < rows; row++ ) + for( row = 0; row < rows; row++ ) { - for( int addr = 0; addr < bytesPerRow; addr++ ) + int addr; + + for( addr = 0; addr < bytesPerRow; addr++ ) { if( currentByte < dataLength ) { @@ -121,7 +128,9 @@ NSString *result; unsigned long bytesEncoded = ([data length] + 1) / 3; char *buffer = (char *) malloc( bytesEncoded ), hex1, hex2; - for( int i = 0; i < bytesEncoded; i++ ) + int i; + + for( i = 0; i < bytesEncoded; i++ ) { hex1 = ((char *)[data bytes])[3*i]; hex2 = ((char *)[data bytes])[3*i+1]; diff --git a/Cocoa/Plug-Ins/Hex Editor/HexTextView.m b/Cocoa/Plug-Ins/Hex Editor/HexTextView.m index d554a08..b9fa792 100644 --- a/Cocoa/Plug-Ins/Hex Editor/HexTextView.m +++ b/Cocoa/Plug-Ins/Hex Editor/HexTextView.m @@ -264,6 +264,7 @@ static NSRange draggedRange; NSPasteboard *pb = [sender draggingPasteboard]; NSData *pastedData = [pb dataForType:NSStringPboardType]; int charIndex = [self _insertionGlyphIndexForDrag:sender]; + NSRange selection; // convert hex string to data if( [sender draggingSource] == [[self delegate] hex] ) @@ -293,7 +294,7 @@ static NSRange draggedRange; [self editData:[[[self window] windowController] data] replaceBytesInRange:NSMakeRange(charIndex,0) withData:pastedData]; // set the new selection/insertion point - NSRange selection = [self rangeForUserTextChange]; + selection = [self rangeForUserTextChange]; selection.location -= draggedRange.length; selection.length = draggedRange.length; [self setSelectedRange:selection]; @@ -327,8 +328,9 @@ static NSRange draggedRange; if( self == (id) [[self delegate] hex] ) { + int i; // bug: iteration through each character in string is broken, paste not yet mapped to this function - for( int i = 0; i < [string cStringLength]; i++ ) + for( i = 0; i < [string cStringLength]; i++ ) { char typedChar = [string characterAtIndex:i]; if( typedChar >= 0x30 && typedChar <= 0x39 ) typedChar -= 0x30; // 0 to 9 diff --git a/Cocoa/Plug-Ins/Hex Editor/HexWindowController.m b/Cocoa/Plug-Ins/Hex Editor/HexWindowController.m index d2e11e9..6df6f4b 100644 --- a/Cocoa/Plug-Ins/Hex Editor/HexWindowController.m +++ b/Cocoa/Plug-Ins/Hex Editor/HexWindowController.m @@ -47,11 +47,6 @@ OSStatus Plug_InitInstance( Plug_PlugInRef plug, Plug_ResourceRef resource ) return self; } -- (id)initWithResources:(id)newResource, ... -{ - return nil; -} - - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; diff --git a/Cocoa/Plug-Ins/ResKnifePluginProtocol.h b/Cocoa/Plug-Ins/ResKnifePluginProtocol.h index 241bc42..f6460f8 100644 --- a/Cocoa/Plug-Ins/ResKnifePluginProtocol.h +++ b/Cocoa/Plug-Ins/ResKnifePluginProtocol.h @@ -1,14 +1,60 @@ #import #import "ResKnifeResourceProtocol.h" -/* Your plug-in's principle class must implement initWithResource: else it won't be loaded by ResKnife (so neh-neh!), all other methods are optional */ - +/* 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 -/*! @function 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. +/*! @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; + +@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; +/*! @method extensionForImageFileExport: + @abstract If you implement imageForImageFileExport, return a string here that + provides the proper file extension for your file. By default the + host application substitutes "tiff" here. */ ++(NSString*) extensionForImageFileExport: (id )theRes; + +@end + + +/* 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, ...; @end \ No newline at end of file diff --git a/Cocoa/Plug-Ins/ResKnifeResourceProtocol.h b/Cocoa/Plug-Ins/ResKnifeResourceProtocol.h index 0c1dd72..0348481 100644 --- a/Cocoa/Plug-Ins/ResKnifeResourceProtocol.h +++ b/Cocoa/Plug-Ins/ResKnifeResourceProtocol.h @@ -1,22 +1,57 @@ +/* ============================================================================= + PROJECT: ResKnife + FILE: ResKnifeResourceProtocol.h + + PURPOSE: This protocol wraps up whatever implementation the host + application (i.e. ResKnife) uses for resources in a way that + every editor can get enough information about the resource + being edited. + + Or in Nick's immortal words (which I found only *after* I had + written the stuff above): + + This protocol allows your plug to interrogate a resource to + find out information about it. + + AUTHORS: Nick Shanks, nick(at)nickshanks.com, (c) ~2001. + M. Uli Kusterer, witness(at)zathras.de, (c) 2003. + + REVISIONS: + 2003-07-31 UK Added document accessor, commented. + ========================================================================== */ + +/* ----------------------------------------------------------------------------- + Headers: + -------------------------------------------------------------------------- */ + #import -/* This protocol allows your plug to interrogate a resource to find out information about it. */ + +/* ----------------------------------------------------------------------------- + Protocol: + -------------------------------------------------------------------------- */ @protocol ResKnifeResourceProtocol -- (void)touch; -- (BOOL)isDirty; -- (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; +-(void) touch; +-(BOOL) isDirty; + +-(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; + +-(NSDocument*) document; // Owner of this resource. Useful for looking for resources in same file as yours. // 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. @@ -31,8 +66,11 @@ @end -// Resource notifications -// See note in Notifications.m about usage +/* ----------------------------------------------------------------------------- + Resource Notifications: + See note in Notifications.m about usage. + -------------------------------------------------------------------------- */ + extern NSString *ResourceWillChangeNotification; extern NSString *ResourceNameWillChangeNotification; extern NSString *ResourceTypeWillChangeNotification; diff --git a/Cocoa/Plug-Ins/Template Editor/TemplateWindowController.h b/Cocoa/Plug-Ins/Template Editor/TemplateWindowController.h index dddedaa..9e7aa4f 100644 --- a/Cocoa/Plug-Ins/Template Editor/TemplateWindowController.h +++ b/Cocoa/Plug-Ins/Template Editor/TemplateWindowController.h @@ -3,7 +3,7 @@ #import "ResKnifePluginProtocol.h" #import "ResKnifeResourceProtocol.h" -@interface TemplateWindowController : NSWindowController +@interface TemplateWindowController : NSWindowController { IBOutlet NSView *containerView; diff --git a/Cocoa/Plug-Ins/Template Editor/TemplateWindowController.m b/Cocoa/Plug-Ins/Template Editor/TemplateWindowController.m index a1cfe4b..e24a487 100644 --- a/Cocoa/Plug-Ins/Template Editor/TemplateWindowController.m +++ b/Cocoa/Plug-Ins/Template Editor/TemplateWindowController.m @@ -171,9 +171,11 @@ // while( currentTemplateElement = [enumerator nextObject] ) while( position < [[resource size] unsignedLongValue] ) { + unsigned long type; + currentTemplateElement = [tmpl objectAtIndex:n]; n++, c++; - unsigned long type = [currentTemplateElement typeAsLong]; + type = [currentTemplateElement typeAsLong]; resourceElement = [[currentTemplateElement copy] autorelease]; NSLog( @"tmpl element = %@; position = %d", currentTemplateElement, position ); switch( type ) diff --git a/Cocoa/Resources/Export.tiff b/Cocoa/Resources/Export.tiff new file mode 100644 index 0000000000000000000000000000000000000000..f08cde585ff62b3bc486c9592cdbb38b767920b2 GIT binary patch literal 17852 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 WnVUKi4DRtz1^~2<+*O7!JpKWqOT~i# literal 0 HcmV?d00001 diff --git a/Cocoa/main.m b/Cocoa/main.m new file mode 100644 index 0000000..2a4380a --- /dev/null +++ b/Cocoa/main.m @@ -0,0 +1,6 @@ +#import + +int main(int argc, const char *argv[]) +{ + return NSApplicationMain(argc, argv); +} \ No newline at end of file diff --git a/NovaTools/Structs.h b/NovaTools/Structs.h index 98bc34e..f62ea08 100644 --- a/NovaTools/Structs.h +++ b/NovaTools/Structs.h @@ -2,7 +2,8 @@ #import -#pragma options align=packed +#pragma options align=mac68k +//#pragma options align=packed // TODO: This doesn't compile in PB (but it does in xCode). // 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. diff --git a/NovaTools/char/CharWindowController.m b/NovaTools/char/CharWindowController.m index fd56035..1afbb52 100644 --- a/NovaTools/char/CharWindowController.m +++ b/NovaTools/char/CharWindowController.m @@ -4,6 +4,10 @@ - (id)initWithResource:(id )newResource { + NSString *tempPrefix; + NSString *tempSuffix; + NSString *tempStart; + self = [self initWithWindowNibName:@"char"]; if( !self ) return nil; @@ -66,9 +70,9 @@ cash = [[NSNumber alloc] initWithLong:charRec->startCash]; kills = [[NSNumber alloc] initWithShort:charRec->startKills]; date = [[NSCalendarDate alloc] initWithYear:charRec->startYear month:charRec->startMonth day:charRec->startDay hour:0 minute:0 second:0 timeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]]; - NSString *tempPrefix = [[[NSString alloc] initWithData:[NSData dataWithBytes:charRec->Prefix length:16] encoding:NSMacOSRomanStringEncoding] autorelease]; + tempPrefix = [[[NSString alloc] initWithData:[NSData dataWithBytes:charRec->Prefix length:16] encoding:NSMacOSRomanStringEncoding] autorelease]; prefix = [[NSString alloc] initWithCString:[tempPrefix cString] length:[tempPrefix cStringLength]]; - NSString *tempSuffix = [[[NSString alloc] initWithData:[NSData dataWithBytes:charRec->Suffix length:16] encoding:NSMacOSRomanStringEncoding] autorelease]; + tempSuffix = [[[NSString alloc] initWithData:[NSData dataWithBytes:charRec->Suffix length:16] encoding:NSMacOSRomanStringEncoding] autorelease]; suffix = [[NSString alloc] initWithCString:[tempSuffix cString] length:[tempSuffix cStringLength]]; start1 = [[NSNumber alloc] initWithShort:charRec->startSystem[0]]; start2 = [[NSNumber alloc] initWithShort:charRec->startSystem[1]]; @@ -91,7 +95,7 @@ introDelay2 = [[NSNumber alloc] initWithShort:charRec->introPictDelay[1]]; introDelay3 = [[NSNumber alloc] initWithShort:charRec->introPictDelay[2]]; introDelay4 = [[NSNumber alloc] initWithShort:charRec->introPictDelay[3]]; - NSString *tempStart = [[[NSString alloc] initWithData:[NSData dataWithBytes:charRec->OnStart length:256] encoding:NSMacOSRomanStringEncoding] autorelease]; + tempStart = [[[NSString alloc] initWithData:[NSData dataWithBytes:charRec->OnStart length:256] encoding:NSMacOSRomanStringEncoding] autorelease]; onStart = [[NSString alloc] initWithCString:[tempStart cString] length:[tempStart cStringLength]]; // rotating image @@ -162,6 +166,8 @@ - (void)update { + NSData *stringData; + // principal character [principalCharButton setState:principalChar]; @@ -207,7 +213,7 @@ [introPictField4 setObjectValue:[pictureDataSource stringValueForResID:introPict4]]; [introTextField setObjectValue:[descriptionDataSource stringValueForResID:introText]]; - NSData *stringData = [(id )[NSClassFromString(@"Resource") getResourceOfType:[plugBundle localizedStringForKey:@"desc" value:@"" table:@"Resource Types"] andID:introText inDocument:nil] data]; + stringData = [(id )[NSClassFromString(@"Resource") getResourceOfType:[plugBundle localizedStringForKey:@"desc" value:@"" table:@"Resource Types"] andID:introText inDocument:nil] data]; if( stringData != nil ) { [introTextView setString:[[[NSString alloc] initWithData:stringData encoding:NSMacOSRomanStringEncoding] autorelease]]; diff --git a/Prefix Files/C99 Prefix.h b/Prefix Files/C99 Prefix.h index f2e5ed0..7c595be 100644 --- a/Prefix Files/C99 Prefix.h +++ b/Prefix Files/C99 Prefix.h @@ -1 +1 @@ -#undef __STDC_VERSION__ \ No newline at end of file +//#undef __STDC_VERSION__ \ No newline at end of file