mirror of
https://github.com/nickshanks/ResKnife.git
synced 2024-06-01 02:41:30 +00:00
Allow the rebase of foreign repositories onto master.
Restores the NuTemplateEditor directory deleted from Git but not from SVN. Foreign repos were forked from SVN tree
This commit is contained in:
parent
8c3386497a
commit
fee2452785
38
Cocoa/TEMPLATE EDITOR.txt
Normal file
38
Cocoa/TEMPLATE EDITOR.txt
Normal file
|
@ -0,0 +1,38 @@
|
|||
ABOUT THE CODE
|
||||
--------------
|
||||
|
||||
|
||||
WHAT HAPPENS WHEN A TEMPLATE EDITOR IS OPENED FOR A RESOURCE
|
||||
|
||||
The template editor uses a dedicated class for each field type (or family of field types).
|
||||
These classes are all subclasses of the common base class NuTemplateElement. For things like
|
||||
lists, there is a subclass NuTemplateGroupElement from which you can instead subclass to
|
||||
have some of the work done for you.
|
||||
|
||||
When opening a resource, the template editor first creates a NuTemplateStream for the template
|
||||
resource and calls readOneObject: on it until it runs out of data, instantiating a hierarchy
|
||||
of NuTemplateElement subclasses for based on the template.
|
||||
|
||||
After that, it creates a NuTemplateStream for the resource and loops over the template object
|
||||
hierarchy, creating a copy of each item, and then calling readDataFrom:containingArray: on
|
||||
the copy, which in turn reads data from the NuTemplateStream and stores it in its instance
|
||||
variables. For this to work, subclasses of NuTemplateElement *must* implement the NSCopying
|
||||
protocol.
|
||||
|
||||
This results in an object hierarchy that describes the entire resource using template fields
|
||||
containing the data, which can now be edited, displayed in lists, etc.
|
||||
|
||||
|
||||
WHAT HAPPENS WHEN THE TEMPLATE EDITOR IS CLOSED
|
||||
|
||||
As soon as the template editor is closed, another NuTemplateStream is created for the
|
||||
resource and passed to all template fields (the copies with the resource data, not the
|
||||
pre-parsed template hierarchy), via writeDataTo:, which is where they should write their
|
||||
data to the stream. Before that, sizeOnDisk is called on each NuTemplateElement to
|
||||
calculate the new size of the resource before the actual process of writing them out.
|
||||
This size must include the size of all of their sub-items, and writeDataTo: must call
|
||||
these sub items if they are to be written to disk.
|
||||
|
||||
|
||||
SPECIAL CASE: LISTS
|
||||
|
68
NuTemplateEditor/Element.h
Normal file
68
NuTemplateEditor/Element.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#import "TemplateStream.h"
|
||||
|
||||
/*
|
||||
This is the base class for all template field types. Subclass this to
|
||||
define a field type of your own.
|
||||
|
||||
Note that subclasses *must* implement the NSCopying protocol, which means
|
||||
if you have instance variables, you must provide your own copyWithZone:
|
||||
implementation that calls through to the superclass and then copies its
|
||||
own variables' values (or retains references to them, if that is more
|
||||
effective and the object in question isn't mutable).
|
||||
*/
|
||||
|
||||
@interface Element : NSObject <NSCopying>
|
||||
{
|
||||
BOOL _isTMPL; // for debugging
|
||||
NSString *type; // Type code of this item (4 chars if from TMPL resource, but we may support longer types later).
|
||||
NSString *label; // Label ("name") of this field.
|
||||
NSMutableArray *parentArray; // The NSMutableArray* of the template field containing us, or the template window's list.
|
||||
}
|
||||
|
||||
+ (id)elementForType:(NSString *)type withLabel:(NSString *)label;
|
||||
- (id)initForType:(NSString *)type withLabel:(NSString *)label;
|
||||
|
||||
// This is used to instantiate copies of the item from the template for storing data of the resource. A copy created with this is then sent readDataFrom:.
|
||||
- (id)copyWithZone:(NSZone *)zone;
|
||||
|
||||
// Accessors:
|
||||
- (void)setIsTMPL:(BOOL)t;
|
||||
- (BOOL)isTMPL;
|
||||
|
||||
- (void)setType:(NSString *)t;
|
||||
- (NSString *)type;
|
||||
|
||||
- (void)setLabel:(NSString *)l;
|
||||
- (NSString *)label;
|
||||
|
||||
- (void)setParentArray:(NSMutableArray *)array;
|
||||
- (NSMutableArray *)parentArray;
|
||||
|
||||
- (NSString *)stringValue; // Used to display your data in the list.
|
||||
- (BOOL)editable;
|
||||
|
||||
// Items that have sub-items (like LSTB, LSTZ, LSTC and other lists) should implement these:
|
||||
- (int)subElementCount;
|
||||
- (Element *)subElementAtIndex:(int)n;
|
||||
- (void)readSubElementsFrom:(TemplateStream *)stream;
|
||||
|
||||
// This is called on an item of your class when displaying resource data using a template that uses your field:
|
||||
- (void)readDataFrom:(TemplateStream *)stream;
|
||||
|
||||
// The following are used to write resource data back out:
|
||||
- (unsigned int)sizeOnDisk;
|
||||
- (void)writeDataTo:(TemplateStream *)stream;
|
||||
|
||||
/* Apart from these messages, a Element may also implement the IBActions for
|
||||
the standard edit commands (cut, copy, paste, clear). When an element is selected,
|
||||
the template editor will forward any calls to these items to the element, if it
|
||||
implements them, and it will automatically enable the appropriate menu items. It
|
||||
will also forward validateMenuItem:for the Paste menu item to the element.
|
||||
|
||||
The createListEntry:action will also be forwarded to elements by the
|
||||
template editor. Use this to allow creating new list items or for similar
|
||||
purposes ("Create New Resource..." is renamed to "Create List Entry" while the
|
||||
template editor is key). */
|
||||
|
||||
@end
|
142
NuTemplateEditor/Element.m
Normal file
142
NuTemplateEditor/Element.m
Normal file
|
@ -0,0 +1,142 @@
|
|||
#import "Element.h"
|
||||
|
||||
@implementation Element
|
||||
|
||||
+ (id)elementForType:(NSString *)t withLabel:(NSString *)l
|
||||
{
|
||||
return [[[self alloc] autorelease] initForType:t withLabel:l];
|
||||
}
|
||||
|
||||
- (id)initForType:(NSString *)t withLabel:(NSString *)l
|
||||
{
|
||||
self = [super init];
|
||||
if(!self) return nil;
|
||||
label = [l copy];
|
||||
type = [t copy];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[label release];
|
||||
[type release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
Element *element = [[[self class] allocWithZone:zone] initForType:type withLabel:label];
|
||||
[element setParentArray:parentArray];
|
||||
return element;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)setIsTMPL:(BOOL)t
|
||||
{
|
||||
_isTMPL = t;
|
||||
}
|
||||
|
||||
- (BOOL)isTMPL
|
||||
{
|
||||
return _isTMPL;
|
||||
}
|
||||
|
||||
- (void)setType:(NSString *)t
|
||||
{
|
||||
id old = type;
|
||||
type = [t copy];
|
||||
[old release];
|
||||
}
|
||||
|
||||
- (NSString *)type
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
- (void)setLabel:(NSString *)l
|
||||
{
|
||||
id old = label;
|
||||
label = [l copy];
|
||||
[old release];
|
||||
}
|
||||
|
||||
- (NSString *)label
|
||||
{
|
||||
return label;
|
||||
}
|
||||
|
||||
- (void)setParentArray:(NSMutableArray *)array
|
||||
{
|
||||
// do not retain parent object
|
||||
parentArray = array;
|
||||
}
|
||||
|
||||
- (NSMutableArray *)parentArray
|
||||
{
|
||||
return parentArray;
|
||||
}
|
||||
|
||||
/*** METHODS SUBCLASSES SHOULD OVERRIDE ***/
|
||||
|
||||
- (int)subElementCount
|
||||
{
|
||||
// default implementation suitable for most element types
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (Element *)subElementAtIndex:(int)n
|
||||
{
|
||||
// default implementation suitable for most element types
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)readSubElementsFrom:(TemplateStream *)stream
|
||||
{
|
||||
// by default, items don't read any sub-elements.
|
||||
}
|
||||
|
||||
// You should read whatever kind of data your template field stands for from "stream"
|
||||
// and store it in an instance variable.
|
||||
- (void)readDataFrom:(TemplateStream *)stream
|
||||
{
|
||||
NSLog(@"-readDataFrom:called on non-concrete class Element");
|
||||
}
|
||||
|
||||
// Before writeDataTo:is called, this is called to calculate the final resource size:
|
||||
// Items with sub-elements should return the sum of the sizes of all their sub-elements here as well.
|
||||
- (unsigned int)sizeOnDisk
|
||||
{
|
||||
// default implementation suitable for dimentionless element types
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (void)writeDataTo:(TemplateStream *)stream
|
||||
{
|
||||
NSLog(@"-writeDataTo:called on non-concrete class Element");
|
||||
}
|
||||
|
||||
- (NSString *)stringValue
|
||||
{
|
||||
NSLog(@"-stringValue called on non-concrete class Element");
|
||||
return @"<unknown>";
|
||||
}
|
||||
|
||||
- (void)setStringValue:(NSString *)value
|
||||
{
|
||||
// we need this method, otherwise KVC throws an exception which screws up the table
|
||||
NSLog(@"-setStringValue:@\"%@\" called on non-concrete class Element", value);
|
||||
}
|
||||
|
||||
- (BOOL)editable
|
||||
{
|
||||
// override this for non-editable field types
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (float)rowHeight
|
||||
{
|
||||
return 18.0;
|
||||
}
|
||||
|
||||
@end
|
12
NuTemplateEditor/ElementDATE.h
Normal file
12
NuTemplateEditor/ElementDATE.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#import "Element.h"
|
||||
|
||||
@interface ElementDATE : Element
|
||||
{
|
||||
// seconds since 1 Jan 1904
|
||||
UInt32 value;
|
||||
}
|
||||
- (UInt32)value;
|
||||
- (void)setValue:(UInt32)v;
|
||||
- (NSString *)stringValue;
|
||||
- (void)setStringValue:(NSString *)str;
|
||||
@end
|
64
NuTemplateEditor/ElementDATE.m
Normal file
64
NuTemplateEditor/ElementDATE.m
Normal file
|
@ -0,0 +1,64 @@
|
|||
#import "ElementDATE.h"
|
||||
|
||||
@implementation ElementDATE
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
ElementDATE *element = [super copyWithZone:zone];
|
||||
[element setValue:value];
|
||||
return element;
|
||||
}
|
||||
|
||||
- (void)readDataFrom:(TemplateStream *)stream
|
||||
{
|
||||
[stream readAmount:sizeof(value) toBuffer:&value];
|
||||
}
|
||||
|
||||
- (unsigned int)sizeOnDisk
|
||||
{
|
||||
return sizeof(value);
|
||||
}
|
||||
|
||||
- (void)writeDataTo:(TemplateStream *)stream
|
||||
{
|
||||
[stream writeAmount:sizeof(value) fromBuffer:&value];
|
||||
}
|
||||
|
||||
- (UInt32)value
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
- (void)setValue:(UInt32)v
|
||||
{
|
||||
value = v;
|
||||
}
|
||||
|
||||
- (NSString *)stringValue
|
||||
{
|
||||
CFAbsoluteTime cfTime;
|
||||
OSStatus error = UCConvertSecondsToCFAbsoluteTime(value, &cfTime);
|
||||
if(error) return nil;
|
||||
// return [[NSCalendarDate dateWithTimeIntervalSinceReferenceDate:(NSTimeInterval)cfTime] descriptionWithLocale:[NSLocale currentLocale]];
|
||||
return [[NSCalendarDate dateWithTimeIntervalSinceReferenceDate:(NSTimeInterval)cfTime] descriptionWithLocale:[NSDictionary dictionaryWithObject:[[NSUserDefaults standardUserDefaults] objectForKey:NSShortTimeDateFormatString] forKey:@"NSTimeDateFormatString"]];
|
||||
// return [[NSCalendarDate dateWithTimeIntervalSinceReferenceDate:(NSTimeInterval)cfTime] descriptionWithLocale:[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
// [[NSUserDefaults standardUserDefaults] objectForKey:NSShortTimeDateFormatString], @"NSTimeDateFormatString",
|
||||
// [[NSUserDefaults standardUserDefaults] objectForKey:NSAMPMDesignation], @"NSAMPMDesignation",
|
||||
// [[NSUserDefaults standardUserDefaults] objectForKey:NSMonthNameArray], @"NSMonthNameArray",
|
||||
// [[NSUserDefaults standardUserDefaults] objectForKey:NSShortMonthNameArray], @"NSShortMonthNameArray",
|
||||
// [[NSUserDefaults standardUserDefaults] objectForKey:NSWeekDayNameArray], @"NSWeekDayNameArray",
|
||||
// [[NSUserDefaults standardUserDefaults] objectForKey:NSShortWeekDayNameArray], @"NSShortWeekDayNameArray",
|
||||
// nil]];
|
||||
// return [[NSCalendarDate dateWithTimeIntervalSinceReferenceDate:(NSTimeInterval)cfTime] descriptionWithLocale:[NSDictionary dictionaryWithObject:[[NSCalendar currentCalendar] calendarIdentifier] forKey:@"NSLocaleCalendar"]];
|
||||
// return [[NSCalendarDate dateWithTimeIntervalSinceReferenceDate:(NSTimeInterval)cfTime] descriptionWithCalendarFormat:[NSCalendar currentCalendar]];// timeZone:[NSTimeZone localTimeZone] locale:[NSDictionary dictionaryWithObject:[NSCalendar currentCalendar] forKey:@"NSLocaleCalendar"]];
|
||||
|
||||
}
|
||||
|
||||
- (void)setStringValue:(NSString *)str
|
||||
{
|
||||
// UCConvertCFAbsoluteTimeToSeconds((CFAbsoluteTime)[[NSCalendarDate dateWithString:str] timeIntervalSinceReferenceDate], &value);
|
||||
UCConvertCFAbsoluteTimeToSeconds((CFAbsoluteTime)[[NSCalendarDate dateWithNaturalLanguageString:str] timeIntervalSinceReferenceDate], &value);
|
||||
// UCConvertCFAbsoluteTimeToSeconds((CFAbsoluteTime)[[NSCalendarDate dateWithNaturalLanguageString:str locale:[NSDictionary dictionaryWithObject:[NSLocale currentLocale] forKey:@"NSLocale"]] timeIntervalSinceReferenceDate], &value);
|
||||
}
|
||||
|
||||
@end
|
17
NuTemplateEditor/ElementDBYT.h
Normal file
17
NuTemplateEditor/ElementDBYT.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#import "Element.h"
|
||||
|
||||
@interface ElementDBYT : Element
|
||||
{
|
||||
SInt8 value;
|
||||
}
|
||||
|
||||
- (void)setValue:(SInt8)v;
|
||||
- (SInt8)value;
|
||||
|
||||
- (NSString *)stringValue;
|
||||
- (void)setStringValue:(NSString *)str;
|
||||
|
||||
@end
|
||||
|
||||
@interface ElementKBYT : ElementDBYT
|
||||
@end
|
53
NuTemplateEditor/ElementDBYT.m
Normal file
53
NuTemplateEditor/ElementDBYT.m
Normal file
|
@ -0,0 +1,53 @@
|
|||
#import "ElementDBYT.h"
|
||||
|
||||
@implementation ElementDBYT
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
ElementDBYT *element = [super copyWithZone:zone];
|
||||
[element setValue:value];
|
||||
return element;
|
||||
}
|
||||
|
||||
- (void)readDataFrom:(TemplateStream *)stream
|
||||
{
|
||||
[stream readAmount:sizeof(value) toBuffer:&value];
|
||||
}
|
||||
|
||||
- (unsigned int)sizeOnDisk
|
||||
{
|
||||
return sizeof(value);
|
||||
}
|
||||
|
||||
- (void)writeDataTo:(TemplateStream *)stream
|
||||
{
|
||||
[stream writeAmount:sizeof(value) fromBuffer:&value];
|
||||
}
|
||||
|
||||
- (void)setValue:(SInt8)v
|
||||
{
|
||||
value = v;
|
||||
}
|
||||
|
||||
- (SInt8)value
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
- (NSString *)stringValue
|
||||
{
|
||||
return [NSString stringWithFormat:@"%hhd", value];
|
||||
}
|
||||
|
||||
- (void)setStringValue:(NSString *)str
|
||||
{
|
||||
char cstr[256];
|
||||
char *endPtr = cstr + 255;
|
||||
strncpy(cstr, [str cString], 255);
|
||||
value = strtol(cstr, &endPtr, 10);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation ElementKBYT
|
||||
@end
|
14
NuTemplateEditor/ElementDLLG.h
Normal file
14
NuTemplateEditor/ElementDLLG.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#import "Element.h"
|
||||
|
||||
@interface ElementDLLG : Element
|
||||
{
|
||||
SInt64 value;
|
||||
}
|
||||
|
||||
- (void)setValue:(SInt64)v;
|
||||
- (SInt64)value;
|
||||
|
||||
- (NSString *)stringValue;
|
||||
- (void)setStringValue:(NSString *)str;
|
||||
|
||||
@end
|
50
NuTemplateEditor/ElementDLLG.m
Normal file
50
NuTemplateEditor/ElementDLLG.m
Normal file
|
@ -0,0 +1,50 @@
|
|||
#import "ElementDLLG.h"
|
||||
|
||||
@implementation ElementDLLG
|
||||
|
||||
- (id)copyWithZone:(NSZone*)zone
|
||||
{
|
||||
ElementDLLG *element = [super copyWithZone:zone];
|
||||
[element setValue:value];
|
||||
return element;
|
||||
}
|
||||
|
||||
- (void)readDataFrom:(TemplateStream *)stream
|
||||
{
|
||||
[stream readAmount:sizeof(value) toBuffer:&value];
|
||||
}
|
||||
|
||||
- (unsigned int)sizeOnDisk
|
||||
{
|
||||
return sizeof(value);
|
||||
}
|
||||
|
||||
- (void)writeDataTo:(TemplateStream *)stream
|
||||
{
|
||||
[stream writeAmount:sizeof(value) fromBuffer:&value];
|
||||
}
|
||||
|
||||
- (void)setValue:(SInt64)v
|
||||
{
|
||||
value = v;
|
||||
}
|
||||
|
||||
- (SInt64)value
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
- (NSString *)stringValue
|
||||
{
|
||||
return [NSString stringWithFormat:@"%lld", value];
|
||||
}
|
||||
|
||||
- (void)setStringValue:(NSString *)str
|
||||
{
|
||||
char cstr[256];
|
||||
char *endPtr = cstr + 255;
|
||||
strncpy(cstr, [str cString], 255);
|
||||
value = strtoll(cstr, &endPtr, 10);
|
||||
}
|
||||
|
||||
@end
|
17
NuTemplateEditor/ElementDLNG.h
Normal file
17
NuTemplateEditor/ElementDLNG.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#import "Element.h"
|
||||
|
||||
@interface ElementDLNG : Element
|
||||
{
|
||||
SInt32 value;
|
||||
}
|
||||
|
||||
- (void)setValue:(SInt32)v;
|
||||
- (SInt32)value;
|
||||
|
||||
- (NSString *)stringValue;
|
||||
- (void)setStringValue:(NSString *)str;
|
||||
|
||||
@end
|
||||
|
||||
@interface ElementKLNG : ElementDLNG
|
||||
@end
|
53
NuTemplateEditor/ElementDLNG.m
Normal file
53
NuTemplateEditor/ElementDLNG.m
Normal file
|
@ -0,0 +1,53 @@
|
|||
#import "ElementDLNG.h"
|
||||
|
||||
@implementation ElementDLNG
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
ElementDLNG *element = [super copyWithZone:zone];
|
||||
[element setValue:value];
|
||||
return element;
|
||||
}
|
||||
|
||||
- (void)readDataFrom:(TemplateStream *)stream
|
||||
{
|
||||
[stream readAmount:sizeof(value) toBuffer:&value];
|
||||
}
|
||||
|
||||
- (unsigned int)sizeOnDisk
|
||||
{
|
||||
return sizeof(value);
|
||||
}
|
||||
|
||||
- (void)writeDataTo:(TemplateStream *)stream
|
||||
{
|
||||
[stream writeAmount:sizeof(value) fromBuffer:&value];
|
||||
}
|
||||
|
||||
- (void)setValue:(SInt32)v
|
||||
{
|
||||
value = v;
|
||||
}
|
||||
|
||||
- (SInt32)value
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
- (NSString *)stringValue
|
||||
{
|
||||
return [NSString stringWithFormat:@"%ld", value];
|
||||
}
|
||||
|
||||
- (void)setStringValue:(NSString *)str
|
||||
{
|
||||
char cstr[256];
|
||||
char *endPtr = cstr + 255;
|
||||
strncpy(cstr, [str cString], 255);
|
||||
value = strtol(cstr, &endPtr, 10);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation ElementKLNG
|
||||
@end
|
17
NuTemplateEditor/ElementDWRD.h
Normal file
17
NuTemplateEditor/ElementDWRD.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#import "Element.h"
|
||||
|
||||
@interface ElementDWRD : Element
|
||||
{
|
||||
SInt16 value;
|
||||
}
|
||||
|
||||
- (void)setValue:(SInt16)v;
|
||||
- (SInt16)value;
|
||||
|
||||
- (NSString *)stringValue;
|
||||
- (void)setStringValue:(NSString *)str;
|
||||
|
||||
@end
|
||||
|
||||
@interface ElementKWRD : ElementDWRD
|
||||
@end
|
53
NuTemplateEditor/ElementDWRD.m
Normal file
53
NuTemplateEditor/ElementDWRD.m
Normal file
|
@ -0,0 +1,53 @@
|
|||
#import "ElementDWRD.h"
|
||||
|
||||
@implementation ElementDWRD
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
ElementDWRD *element = [super copyWithZone:zone];
|
||||
[element setValue:value];
|
||||
return element;
|
||||
}
|
||||
|
||||
- (void)readDataFrom:(TemplateStream *)stream
|
||||
{
|
||||
[stream readAmount:sizeof(value) toBuffer:&value];
|
||||
}
|
||||
|
||||
- (unsigned int)sizeOnDisk
|
||||
{
|
||||
return sizeof(value);
|
||||
}
|
||||
|
||||
- (void)writeDataTo:(TemplateStream *)stream
|
||||
{
|
||||
[stream writeAmount:sizeof(value) fromBuffer:&value];
|
||||
}
|
||||
|
||||
- (void)setValue:(SInt16)v
|
||||
{
|
||||
value = v;
|
||||
}
|
||||
|
||||
- (SInt16)value
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
- (NSString *)stringValue
|
||||
{
|
||||
return [NSString stringWithFormat:@"%hd", value];
|
||||
}
|
||||
|
||||
- (void)setStringValue:(NSString *)str
|
||||
{
|
||||
char cstr[256];
|
||||
char *endPtr = cstr + 255;
|
||||
strncpy(cstr, [str cString], 255);
|
||||
value = strtol(cstr, &endPtr, 10);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation ElementKWRD
|
||||
@end
|
14
NuTemplateEditor/ElementFBYT.h
Normal file
14
NuTemplateEditor/ElementFBYT.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#import "Element.h"
|
||||
|
||||
@interface ElementFBYT : Element
|
||||
{
|
||||
unsigned long length;
|
||||
}
|
||||
|
||||
- (void)setLength:(unsigned long)l;
|
||||
- (unsigned long)length;
|
||||
|
||||
- (NSString *)stringValue;
|
||||
- (void)setStringValue:(NSString *)str;
|
||||
|
||||
@end
|
70
NuTemplateEditor/ElementFBYT.m
Normal file
70
NuTemplateEditor/ElementFBYT.m
Normal file
|
@ -0,0 +1,70 @@
|
|||
#import "ElementFBYT.h"
|
||||
|
||||
// implements FBYT, FWRD, FLNG, FLLG
|
||||
@implementation ElementFBYT
|
||||
|
||||
- (id)initForType:(NSString *)t withLabel:(NSString *)l
|
||||
{
|
||||
self = [super initForType:t withLabel:l];
|
||||
if(!self) return nil;
|
||||
if ([t isEqualToString:@"FBYT"]) length = 1;
|
||||
else if([t isEqualToString:@"FWRD"]) length = 2;
|
||||
else if([t isEqualToString:@"FLNG"]) length = 4;
|
||||
else if([t isEqualToString:@"FLLG"]) length = 8;
|
||||
else length = 0;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
ElementFBYT *element = [super copyWithZone:zone];
|
||||
[element setLength:length];
|
||||
return element;
|
||||
}
|
||||
|
||||
- (void)readDataFrom:(TemplateStream *)stream
|
||||
{
|
||||
[stream advanceAmount:length pad:NO];
|
||||
}
|
||||
|
||||
- (unsigned int)sizeOnDisk
|
||||
{
|
||||
return length;
|
||||
}
|
||||
|
||||
- (void)writeDataTo:(TemplateStream *)stream
|
||||
{
|
||||
[stream advanceAmount:length pad:YES];
|
||||
}
|
||||
|
||||
- (void)setLength:(unsigned long)l
|
||||
{
|
||||
length = l;
|
||||
}
|
||||
|
||||
- (unsigned long)length
|
||||
{
|
||||
return length;
|
||||
}
|
||||
|
||||
- (NSString *)stringValue
|
||||
{
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (void)setStringValue:(NSString *)str
|
||||
{
|
||||
}
|
||||
|
||||
- (NSString *)label
|
||||
{
|
||||
if(length) return @"";
|
||||
return [super label];
|
||||
}
|
||||
|
||||
- (BOOL)editable
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
14
NuTemplateEditor/ElementFIXD.h
Normal file
14
NuTemplateEditor/ElementFIXD.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#import "Element.h"
|
||||
|
||||
@interface ElementFIXD : Element
|
||||
{
|
||||
Fixed value;
|
||||
}
|
||||
|
||||
- (void)setValue:(Fixed)v;
|
||||
- (Fixed)value;
|
||||
|
||||
- (NSString *)stringValue;
|
||||
- (void)setStringValue:(NSString *)str;
|
||||
|
||||
@end
|
50
NuTemplateEditor/ElementFIXD.m
Normal file
50
NuTemplateEditor/ElementFIXD.m
Normal file
|
@ -0,0 +1,50 @@
|
|||
#import "ElementFIXD.h"
|
||||
|
||||
@implementation ElementFIXD
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
ElementFIXD *element = [super copyWithZone:zone];
|
||||
[element setValue:value];
|
||||
return element;
|
||||
}
|
||||
|
||||
- (void)readDataFrom:(TemplateStream *)stream
|
||||
{
|
||||
[stream readAmount:sizeof(value) toBuffer:&value];
|
||||
}
|
||||
|
||||
- (unsigned int)sizeOnDisk
|
||||
{
|
||||
return sizeof(value);
|
||||
}
|
||||
|
||||
- (void)writeDataTo:(TemplateStream *)stream
|
||||
{
|
||||
[stream writeAmount:sizeof(value) fromBuffer:&value];
|
||||
}
|
||||
|
||||
- (void)setValue:(Fixed)v
|
||||
{
|
||||
value = v;
|
||||
}
|
||||
|
||||
- (Fixed)value
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
- (NSString *)stringValue
|
||||
{
|
||||
return [NSString stringWithFormat:@"%.3lf", FixedToFloat(value)];
|
||||
}
|
||||
|
||||
- (void)setStringValue:(NSString *)str
|
||||
{
|
||||
char cstr[256];
|
||||
char *endPtr = cstr + 255;
|
||||
strncpy(cstr, [str cString], 255);
|
||||
value = FloatToFixed(strtof(cstr, &endPtr));
|
||||
}
|
||||
|
||||
@end
|
14
NuTemplateEditor/ElementFRAC.h
Normal file
14
NuTemplateEditor/ElementFRAC.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#import "Element.h"
|
||||
|
||||
@interface ElementFRAC : Element
|
||||
{
|
||||
Fract value;
|
||||
}
|
||||
|
||||
- (void)setValue:(Fract)v;
|
||||
- (Fract)value;
|
||||
|
||||
- (NSString *)stringValue;
|
||||
- (void)setStringValue:(NSString *)str;
|
||||
|
||||
@end
|
50
NuTemplateEditor/ElementFRAC.m
Normal file
50
NuTemplateEditor/ElementFRAC.m
Normal file
|
@ -0,0 +1,50 @@
|
|||
#import "ElementFRAC.h"
|
||||
|
||||
@implementation ElementFRAC
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
ElementFRAC *element = [super copyWithZone:zone];
|
||||
[element setValue:value];
|
||||
return element;
|
||||
}
|
||||
|
||||
- (void)readDataFrom:(TemplateStream *)stream
|
||||
{
|
||||
[stream readAmount:sizeof(value) toBuffer:&value];
|
||||
}
|
||||
|
||||
- (unsigned int)sizeOnDisk
|
||||
{
|
||||
return sizeof(value);
|
||||
}
|
||||
|
||||
- (void)writeDataTo:(TemplateStream *)stream
|
||||
{
|
||||
[stream writeAmount:sizeof(value) fromBuffer:&value];
|
||||
}
|
||||
|
||||
- (void)setValue:(Fract)v
|
||||
{
|
||||
value = v;
|
||||
}
|
||||
|
||||
- (Fract)value
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
- (NSString *)stringValue
|
||||
{
|
||||
return [NSString stringWithFormat:@"%.10lg", FractToFloat(value)];
|
||||
}
|
||||
|
||||
- (void)setStringValue:(NSString *)str
|
||||
{
|
||||
char cstr[256];
|
||||
char *endPtr = cstr + 255;
|
||||
strncpy(cstr, [str cString], 255);
|
||||
value = FloatToFract(strtof(cstr, &endPtr));
|
||||
}
|
||||
|
||||
@end
|
13
NuTemplateEditor/ElementHEXD.h
Normal file
13
NuTemplateEditor/ElementHEXD.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#import "Element.h"
|
||||
|
||||
@interface ElementHEXD : Element
|
||||
{
|
||||
NSData *value;
|
||||
}
|
||||
- (void)setValue:(NSData *)d;
|
||||
- (NSData *)value;
|
||||
|
||||
- (NSString *)stringValue;
|
||||
- (void)setStringValue:(NSString *)str;
|
||||
|
||||
@end
|
64
NuTemplateEditor/ElementHEXD.m
Normal file
64
NuTemplateEditor/ElementHEXD.m
Normal file
|
@ -0,0 +1,64 @@
|
|||
#import "ElementHEXD.h"
|
||||
|
||||
@implementation ElementHEXD
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
ElementHEXD *element = [super copyWithZone:zone];
|
||||
[element setValue:value];
|
||||
return element;
|
||||
}
|
||||
|
||||
- (void)readSubElementsFrom:(TemplateStream *)stream
|
||||
{
|
||||
// override to tell stream to stop reading any more TMPL fields
|
||||
if([stream bytesToGo] > 0)
|
||||
{
|
||||
NSLog(@"Warning: Template has fields following hex dump, ignoring them.");
|
||||
[stream setBytesToGo:0];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)readDataFrom:(TemplateStream *)stream
|
||||
{
|
||||
[self setValue:[NSData dataWithBytes:[stream data] length:[stream bytesToGo]]];
|
||||
[stream setBytesToGo:0];
|
||||
}
|
||||
|
||||
- (unsigned int)sizeOnDisk
|
||||
{
|
||||
return [value length];
|
||||
}
|
||||
|
||||
- (void)writeDataTo:(TemplateStream *)stream
|
||||
{
|
||||
[stream writeAmount:[value length] fromBuffer:[value bytes]];
|
||||
}
|
||||
|
||||
- (void)setValue:(NSData *)d
|
||||
{
|
||||
id old = value;
|
||||
value = [d retain];
|
||||
[old release];
|
||||
}
|
||||
|
||||
- (NSData *)value
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
- (NSString *)stringValue
|
||||
{
|
||||
return [value description];
|
||||
}
|
||||
|
||||
- (void)setStringValue:(NSString *)str
|
||||
{
|
||||
}
|
||||
|
||||
- (BOOL)editable
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
15
NuTemplateEditor/ElementKEYB.h
Normal file
15
NuTemplateEditor/ElementKEYB.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
#import "Element.h"
|
||||
|
||||
@interface ElementKEYB : Element
|
||||
{
|
||||
NSMutableArray *subElements;
|
||||
}
|
||||
|
||||
- (void)setSubElements:(NSMutableArray *)a;
|
||||
- (NSMutableArray *)subElements;
|
||||
|
||||
@end
|
||||
|
||||
@interface ElementKEYE : Element
|
||||
@end
|
105
NuTemplateEditor/ElementKEYB.mm
Normal file
105
NuTemplateEditor/ElementKEYB.mm
Normal file
|
@ -0,0 +1,105 @@
|
|||
#import "ElementKEYB.h"
|
||||
|
||||
@implementation ElementKEYB
|
||||
|
||||
- (id)initForType:(NSString *)t withLabel:(NSString *)l
|
||||
{
|
||||
self = [super initForType:t withLabel:l];
|
||||
if(!self) return nil;
|
||||
subElements = [[NSMutableArray alloc] init];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[subElements release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)readSubElementsFrom:(TemplateStream *)stream
|
||||
{
|
||||
while([stream bytesToGo] > 0)
|
||||
{
|
||||
Element *element = [stream readOneElement];
|
||||
if([[element type] isEqualToString:@"KEYE"])
|
||||
break;
|
||||
[subElements addObject:element];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)readDataFrom:(TemplateStream *)stream
|
||||
{
|
||||
if([[self label] isEqualToString: [[stream key] stringValue]])
|
||||
{
|
||||
for(unsigned i = 0; i < [subElements count]; i++)
|
||||
[[subElements objectAtIndex:i] readDataFrom:stream];
|
||||
}
|
||||
}
|
||||
|
||||
// Before writeDataTo:is called, this is called to calculate the final resource size:
|
||||
// This returns the sizes of all our sub-elements. If you subclass, add to that the size
|
||||
// of this element itself.
|
||||
- (unsigned int)sizeOnDisk
|
||||
{
|
||||
// if(![[self label] isEqualToString: [[stream key] stringValue]])
|
||||
// return 0;
|
||||
|
||||
unsigned int size = 0;
|
||||
NSEnumerator *enumerator = [subElements objectEnumerator];
|
||||
while(Element *element = [enumerator nextObject])
|
||||
size += [element sizeOnDisk];
|
||||
return size;
|
||||
}
|
||||
|
||||
- (void)writeDataTo:(TemplateStream *)stream
|
||||
{
|
||||
if([[self label] isEqualToString: [[stream key] stringValue]])
|
||||
{
|
||||
// writes out the data of all our sub-elements here:
|
||||
NSEnumerator *enumerator = [subElements objectEnumerator];
|
||||
while(Element *element = [enumerator nextObject])
|
||||
[element writeDataTo:stream];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setSubElements:(NSMutableArray *)a
|
||||
{
|
||||
id old = subElements;
|
||||
subElements = [a retain];
|
||||
[old release];
|
||||
}
|
||||
|
||||
- (NSMutableArray *)subElements
|
||||
{
|
||||
return subElements;
|
||||
}
|
||||
|
||||
- (int)subElementCount
|
||||
{
|
||||
return [subElements count];
|
||||
}
|
||||
|
||||
- (Element *)subElementAtIndex:(int)n
|
||||
{
|
||||
return [subElements objectAtIndex:n];
|
||||
}
|
||||
|
||||
- (NSString *)stringValue { return @""; }
|
||||
- (void)setStringValue:(NSString *)str {}
|
||||
- (BOOL)editable { return NO; }
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation ElementKEYE
|
||||
- (void)readDataFrom:(TemplateStream *)stream {}
|
||||
- (void)writeDataTo:(TemplateStream *)stream {}
|
||||
- (NSString *)stringValue { return @""; }
|
||||
- (void)setStringValue:(NSString *)str {}
|
||||
- (BOOL)editable { return NO; }
|
||||
@end
|
26
NuTemplateEditor/ElementLSTB.h
Normal file
26
NuTemplateEditor/ElementLSTB.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
#import "Element.h"
|
||||
|
||||
@class ElementLSTE;
|
||||
@class ElementOCNT;
|
||||
|
||||
@interface ElementLSTB : Element
|
||||
{
|
||||
NSMutableArray *subElements;
|
||||
ElementLSTB *groupElementTemplate; // TMPL equivalent of self, for cloning
|
||||
ElementOCNT *countElement; // Our "list counter" element.
|
||||
}
|
||||
|
||||
- (void)readDataForElements:(TemplateStream *)stream;
|
||||
- (IBAction)createListEntry:(id)sender;
|
||||
|
||||
- (void)setSubElements:(NSMutableArray *)a;
|
||||
- (NSMutableArray *)subElements;
|
||||
|
||||
- (void)setGroupElementTemplate:(ElementLSTB *)e;
|
||||
- (ElementLSTB *)groupElementTemplate;
|
||||
|
||||
- (void)setCountElement:(ElementOCNT *)e;
|
||||
- (ElementOCNT *)countElement;
|
||||
|
||||
@end
|
249
NuTemplateEditor/ElementLSTB.mm
Normal file
249
NuTemplateEditor/ElementLSTB.mm
Normal file
|
@ -0,0 +1,249 @@
|
|||
#import "ElementLSTB.h"
|
||||
#import "ElementLSTC.h"
|
||||
#import "ElementLSTE.h"
|
||||
#import "ElementOCNT.h"
|
||||
|
||||
// implements LSTB, LSTZ
|
||||
@implementation ElementLSTB
|
||||
|
||||
- (id)initForType:(NSString *)t withLabel:(NSString *)l
|
||||
{
|
||||
self = [super initForType:t withLabel:l];
|
||||
if(!self) return nil;
|
||||
subElements = [[NSMutableArray alloc] init];
|
||||
groupElementTemplate = self;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[subElements release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
ElementLSTB *element = [super copyWithZone:zone];
|
||||
if(!element) return nil;
|
||||
|
||||
ElementOCNT *counter = nil;
|
||||
NSMutableArray *array = [element subElements]; // get empty array created by -initWithType:label:
|
||||
[element setGroupElementTemplate:groupElementTemplate]; // override group template (init sets this to self)
|
||||
unsigned count = [[groupElementTemplate subElements] count];
|
||||
for(unsigned i = 0; i < count; i++)
|
||||
{
|
||||
Element *subToClone = [[groupElementTemplate subElements] objectAtIndex:i];
|
||||
if([subToClone class] == [ElementLSTB class] ||
|
||||
[subToClone class] == [ElementLSTC class])
|
||||
{
|
||||
// instead create a terminating 'LSTE' item, using LSTB/C item's label
|
||||
ElementLSTE *end = [ElementLSTE elementForType:@"LSTE" withLabel:[subToClone label]];
|
||||
[array addObject:end];
|
||||
[end setParentArray:array];
|
||||
[end setGroupElementTemplate:[(id)subToClone groupElementTemplate]];
|
||||
[end setCountElement:counter];
|
||||
if([[subToClone type] isEqualToString:@"LSTZ"])
|
||||
[end setWritesZeroByte:YES];
|
||||
}
|
||||
else
|
||||
{
|
||||
Element *clone = [[subToClone copy] autorelease];
|
||||
if([clone class] == [ElementOCNT class])
|
||||
counter = (ElementOCNT *)clone;
|
||||
[array addObject:clone];
|
||||
}
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
- (void)readSubElementsFrom:(TemplateStream *)stream
|
||||
{
|
||||
while([stream bytesToGo] > 0)
|
||||
{
|
||||
Element *element = [stream readOneElement];
|
||||
if([[element type] isEqualToString:@"LSTE"])
|
||||
{
|
||||
if([type isEqualToString:@"LSTZ"])
|
||||
[(ElementLSTE *)element setWritesZeroByte:YES];
|
||||
break;
|
||||
}
|
||||
[subElements addObject:element];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)readDataForElements:(TemplateStream *)stream
|
||||
{
|
||||
int counterValue = 0;
|
||||
ElementOCNT *counter = nil;
|
||||
for(unsigned i = 0; i < [subElements count]; i++)
|
||||
{
|
||||
Element *element = [subElements objectAtIndex:i];
|
||||
|
||||
// set up the counter tracking
|
||||
if([element class] == [ElementOCNT class]) counter = element;
|
||||
|
||||
// decrement the counter if we have list items
|
||||
if([element class] == [ElementLSTC class]) counterValue--;
|
||||
|
||||
// if we get to the end of the list and need more items, create them
|
||||
if([element class] == [ElementLSTE class] && counterValue > 0)
|
||||
{
|
||||
int index = [subElements indexOfObject:element];
|
||||
while(counterValue--)
|
||||
{
|
||||
// create subarray for new data
|
||||
ElementLSTB *list = [[[(ElementLSTE *)element groupElementTemplate] copy] autorelease];
|
||||
[subElements insertObject:list atIndex:index++];
|
||||
[list setParentArray:subElements];
|
||||
[list setCountElement:counter];
|
||||
|
||||
// read data into it and increment loop
|
||||
[list readDataForElements:stream]; i++;
|
||||
}
|
||||
}
|
||||
|
||||
// actually read the data for this item
|
||||
[element readDataFrom:stream];
|
||||
|
||||
// now that we've read the (possibly counter) data, save it to the local variable
|
||||
if(counter) counterValue = [counter value];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)readDataFrom:(TemplateStream *)stream
|
||||
{
|
||||
BOOL isZeroTerminated = [type isEqualToString:@"LSTZ"];
|
||||
unsigned int bytesToGoAtStart = [stream bytesToGo];
|
||||
if(isZeroTerminated)
|
||||
{
|
||||
char termByte = 0;
|
||||
[stream peekAmount:1 toBuffer:&termByte];
|
||||
if(termByte)
|
||||
[self readDataForElements:stream];
|
||||
}
|
||||
else [self readDataForElements:stream];
|
||||
|
||||
/* Read additional elements until we have enough items,
|
||||
except if we're not the first item in our list. */
|
||||
if(parentArray)
|
||||
{
|
||||
while([stream bytesToGo] > 0)
|
||||
{
|
||||
if(isZeroTerminated)
|
||||
{
|
||||
char termByte = 0;
|
||||
[stream peekAmount:1 toBuffer:&termByte];
|
||||
if(termByte == 0) break;
|
||||
}
|
||||
|
||||
// actually read the item
|
||||
Element *nextItem = [[groupElementTemplate copy] autorelease];
|
||||
[nextItem setParentArray:nil]; // Make sure it doesn't get into this "if" clause.
|
||||
[parentArray addObject:nextItem]; // Add it below ourselves.
|
||||
[nextItem readDataFrom:stream]; // Read it the same way we were.
|
||||
[nextItem setParentArray:parentArray]; // Set parentArray *after* -readDataFrom: so it doesn't pass the if(parentArray) check above.
|
||||
}
|
||||
|
||||
// now add a terminating 'LSTE' item, using this item's label
|
||||
ElementLSTE *end = [ElementLSTE elementForType:@"LSTE" withLabel:label];
|
||||
[parentArray addObject:end];
|
||||
[end setParentArray:parentArray];
|
||||
[end setGroupElementTemplate:groupElementTemplate];
|
||||
[end setCountElement:countElement];
|
||||
if(isZeroTerminated)
|
||||
{
|
||||
[end setWritesZeroByte:YES];
|
||||
[end readDataFrom:stream];
|
||||
}
|
||||
|
||||
// if it's an empty list delete this LSTB so we only have the empty LSTE.
|
||||
if(bytesToGoAtStart == 0)
|
||||
[parentArray removeObject:self];
|
||||
}
|
||||
}
|
||||
|
||||
// Before writeDataTo:is called, this is called to calculate the final resource size:
|
||||
// This returns the sizes of all our sub-elements. If you subclass, add to that the size
|
||||
// of this element itself.
|
||||
- (unsigned int)sizeOnDisk
|
||||
{
|
||||
unsigned int size = 0;
|
||||
NSEnumerator *enumerator = [subElements objectEnumerator];
|
||||
while(Element *element = [enumerator nextObject])
|
||||
size += [element sizeOnDisk];
|
||||
return size;
|
||||
}
|
||||
|
||||
- (void)writeDataTo:(TemplateStream *)stream
|
||||
{
|
||||
// Writes out the data of all our sub-elements here:
|
||||
NSEnumerator *enumerator = [subElements objectEnumerator];
|
||||
while(Element *element = [enumerator nextObject])
|
||||
[element writeDataTo:stream];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)setSubElements:(NSMutableArray *)a
|
||||
{
|
||||
id old = subElements;
|
||||
subElements = [a retain];
|
||||
[old release];
|
||||
}
|
||||
|
||||
- (NSMutableArray *)subElements
|
||||
{
|
||||
return subElements;
|
||||
}
|
||||
|
||||
- (int)subElementCount
|
||||
{
|
||||
return [subElements count];
|
||||
}
|
||||
|
||||
- (Element *)subElementAtIndex:(int)n
|
||||
{
|
||||
return [subElements objectAtIndex:n];
|
||||
}
|
||||
|
||||
- (void)setGroupElementTemplate:(ElementLSTB *)e
|
||||
{
|
||||
// do not retain, -init sets this to 'self' initially!
|
||||
groupElementTemplate = e;
|
||||
}
|
||||
|
||||
- (ElementLSTB *)groupElementTemplate
|
||||
{
|
||||
return groupElementTemplate;
|
||||
}
|
||||
|
||||
- (void)setCountElement:(ElementOCNT *)e
|
||||
{
|
||||
// do not retain sibling element
|
||||
countElement = e;
|
||||
}
|
||||
|
||||
- (ElementOCNT *)countElement
|
||||
{
|
||||
return countElement;
|
||||
}
|
||||
|
||||
- (IBAction)createListEntry:(id)sender
|
||||
{
|
||||
ElementLSTB *list = [[groupElementTemplate copy] autorelease];
|
||||
[parentArray insertObject:list atIndex:[parentArray indexOfObject:self]];
|
||||
[list setParentArray:parentArray];
|
||||
[list setCountElement:countElement];
|
||||
[countElement increment];
|
||||
}
|
||||
|
||||
- (IBAction)clear:(id)sender
|
||||
{
|
||||
[countElement decrement];
|
||||
[parentArray removeObject:self];
|
||||
}
|
||||
|
||||
- (NSString *)stringValue { return @""; }
|
||||
- (void)setStringValue:(NSString *)str {}
|
||||
- (BOOL)editable { return NO; }
|
||||
@end
|
4
NuTemplateEditor/ElementLSTC.h
Normal file
4
NuTemplateEditor/ElementLSTC.h
Normal file
|
@ -0,0 +1,4 @@
|
|||
#import "ElementLSTB.h"
|
||||
|
||||
@interface ElementLSTC : ElementLSTB
|
||||
@end
|
60
NuTemplateEditor/ElementLSTC.mm
Normal file
60
NuTemplateEditor/ElementLSTC.mm
Normal file
|
@ -0,0 +1,60 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
#import "ElementLSTC.h"
|
||||
#import "ElementLSTE.h"
|
||||
#import "ElementOCNT.h"
|
||||
|
||||
@implementation ElementLSTC
|
||||
|
||||
- (void)readSubElementsFrom:(TemplateStream *)stream
|
||||
{
|
||||
while([stream bytesToGo] > 0)
|
||||
{
|
||||
Element *element = [stream readOneElement];
|
||||
if([[element type] isEqualToString:@"LSTE"])
|
||||
break;
|
||||
[subElements addObject:element];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)readDataFrom:(TemplateStream *)stream
|
||||
{
|
||||
[self setCountElement:[stream counter]];
|
||||
unsigned int itemsToGo = [countElement value];
|
||||
unsigned int itemsToGoAtStart = itemsToGo;
|
||||
|
||||
// Read a first item:
|
||||
if(itemsToGo > 0)
|
||||
{
|
||||
[self readDataForElements:stream];
|
||||
itemsToGo--;
|
||||
}
|
||||
|
||||
/* Read additional elements until we have enough items,
|
||||
except if we're not the first item in our list. */
|
||||
if(parentArray)
|
||||
{
|
||||
while(itemsToGo--)
|
||||
{
|
||||
// Actually read the item:
|
||||
Element *nextItem = [[groupElementTemplate copy] autorelease]; // Make another list item just like this one.
|
||||
[nextItem setParentArray:nil]; // Make sure it doesn't get into this "if" clause.
|
||||
[parentArray addObject:nextItem]; // Add it below ourselves.
|
||||
[nextItem readDataFrom:stream]; // Read it the same way we were.
|
||||
[nextItem setParentArray:parentArray]; // Set parentArray *after* -readDataFrom: so it doesn't pass the if(parentArray) check above.
|
||||
}
|
||||
|
||||
// now add a terminating 'LSTE' item, using this item's label
|
||||
ElementLSTE *end = [ElementLSTE elementForType:@"LSTE" withLabel:label];
|
||||
[parentArray addObject:end];
|
||||
[end setParentArray:parentArray];
|
||||
[end setGroupElementTemplate:groupElementTemplate];
|
||||
[end setCountElement:countElement];
|
||||
[stream popCounter];
|
||||
|
||||
// if it's an empty list delete this LSTC so we only have the empty LSTE.
|
||||
if(itemsToGoAtStart == 0)
|
||||
[parentArray removeObject:self];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
24
NuTemplateEditor/ElementLSTE.h
Normal file
24
NuTemplateEditor/ElementLSTE.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
#import "Element.h"
|
||||
|
||||
@class ElementOCNT;
|
||||
@class ElementLSTB;
|
||||
@interface ElementLSTE : Element
|
||||
{
|
||||
ElementLSTB *groupElementTemplate; // The item of which we're to create a copy.
|
||||
ElementOCNT *countElement; // The "counter" element if we're the end of an LSTC list.
|
||||
BOOL writesZeroByte; // Write a terminating zero-byte when writing out this item (used by LSTZ).
|
||||
}
|
||||
|
||||
- (IBAction)createListEntry:(id)sender;
|
||||
|
||||
- (void)setWritesZeroByte:(BOOL)n;
|
||||
- (BOOL)writesZeroByte;
|
||||
|
||||
- (void)setGroupElementTemplate:(ElementLSTB *)e;
|
||||
- (ElementLSTB *)groupElementTemplate;
|
||||
|
||||
- (void)setCountElement:(ElementOCNT *)e;
|
||||
- (ElementOCNT *)countElement;
|
||||
|
||||
@end
|
99
NuTemplateEditor/ElementLSTE.m
Normal file
99
NuTemplateEditor/ElementLSTE.m
Normal file
|
@ -0,0 +1,99 @@
|
|||
#import "ElementLSTE.h"
|
||||
#import "ElementLSTB.h"
|
||||
#import "ElementOCNT.h"
|
||||
|
||||
@implementation ElementLSTE
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
ElementLSTE *element = [super copyWithZone:zone];
|
||||
[element setGroupElementTemplate:groupElementTemplate];
|
||||
[element setWritesZeroByte:writesZeroByte];
|
||||
[element setCountElement:countElement];
|
||||
return element;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[groupElementTemplate release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)setGroupElementTemplate:(ElementLSTB *)e
|
||||
{
|
||||
id old = groupElementTemplate;
|
||||
groupElementTemplate = [e retain];
|
||||
[old release];
|
||||
}
|
||||
|
||||
- (ElementLSTB *)groupElementTemplate
|
||||
{
|
||||
return groupElementTemplate;
|
||||
}
|
||||
|
||||
- (void)setCountElement:(ElementOCNT *)e
|
||||
{
|
||||
// do not retain sibling element
|
||||
countElement = e;
|
||||
}
|
||||
|
||||
- (ElementOCNT *)countElement
|
||||
{
|
||||
return countElement;
|
||||
}
|
||||
|
||||
- (void)readSubElementsFrom:(TemplateStream *)stream
|
||||
{
|
||||
}
|
||||
|
||||
- (void)readDataFrom:(TemplateStream *)stream
|
||||
{
|
||||
if(writesZeroByte)
|
||||
[stream advanceAmount:1 pad:NO];
|
||||
}
|
||||
|
||||
- (unsigned int)sizeOnDisk
|
||||
{
|
||||
return writesZeroByte? 1:0;
|
||||
}
|
||||
|
||||
- (void)writeDataTo:(TemplateStream *)stream
|
||||
{
|
||||
if(writesZeroByte)
|
||||
[stream advanceAmount:1 pad:YES];
|
||||
}
|
||||
|
||||
- (void)setWritesZeroByte:(BOOL)n
|
||||
{
|
||||
writesZeroByte = n;
|
||||
}
|
||||
|
||||
- (BOOL)writesZeroByte
|
||||
{
|
||||
return writesZeroByte;
|
||||
}
|
||||
|
||||
- (IBAction)createListEntry:(id)sender
|
||||
{
|
||||
ElementLSTB *list = [[groupElementTemplate copy] autorelease];
|
||||
[parentArray insertObject:list atIndex:[parentArray indexOfObject:self]];
|
||||
[list setParentArray:parentArray];
|
||||
[list setCountElement:countElement];
|
||||
[countElement increment];
|
||||
}
|
||||
|
||||
- (NSString *)stringValue
|
||||
{
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (void)setStringValue:(NSString *)str
|
||||
{
|
||||
}
|
||||
|
||||
- (BOOL)editable
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
19
NuTemplateEditor/ElementOCNT.h
Normal file
19
NuTemplateEditor/ElementOCNT.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#import "Element.h"
|
||||
|
||||
@interface ElementOCNT : Element
|
||||
{
|
||||
unsigned long value;
|
||||
}
|
||||
|
||||
- (BOOL)countFromZero;
|
||||
|
||||
- (void)setValue:(unsigned long)v;
|
||||
- (unsigned long)value;
|
||||
|
||||
- (void)increment;
|
||||
- (void)decrement;
|
||||
|
||||
- (NSString *)stringValue;
|
||||
- (void)setStringValue:(NSString *)str;
|
||||
|
||||
@end
|
85
NuTemplateEditor/ElementOCNT.m
Normal file
85
NuTemplateEditor/ElementOCNT.m
Normal file
|
@ -0,0 +1,85 @@
|
|||
#import "ElementOCNT.h"
|
||||
|
||||
// implements ZCNT, OCNT, BCNT, BZCT, WCNT, WZCT, LCNT, LZCT
|
||||
@implementation ElementOCNT
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
ElementOCNT *element = [super copyWithZone:zone];
|
||||
if(!element) return nil;
|
||||
|
||||
// always reset counter on copy
|
||||
[element setValue:0];
|
||||
return element;
|
||||
}
|
||||
|
||||
- (void)readDataFrom:(TemplateStream *)stream
|
||||
{
|
||||
value = 0;
|
||||
if ([type isEqualToString:@"LCNT"] || [type isEqualToString:@"LZCT"]) [stream readAmount:4 toBuffer:&value];
|
||||
else if([type isEqualToString:@"BCNT"] || [type isEqualToString:@"BZCT"]) [stream readAmount:1 toBuffer:(char *)(&value)+3];
|
||||
else [stream readAmount:2 toBuffer:(short *)(&value)+1];
|
||||
if([self countFromZero]) value += 1;
|
||||
}
|
||||
|
||||
- (unsigned int)sizeOnDisk
|
||||
{
|
||||
if ([type isEqualToString:@"LCNT"] || [type isEqualToString:@"LZCT"]) return 4;
|
||||
else if([type isEqualToString:@"BCNT"] || [type isEqualToString:@"BZCT"]) return 1;
|
||||
else return 2;
|
||||
}
|
||||
|
||||
- (void)writeDataTo:(TemplateStream *)stream
|
||||
{
|
||||
if([self countFromZero]) value -= 1;
|
||||
if ([type isEqualToString:@"LCNT"] || [type isEqualToString:@"LZCT"]) [stream writeAmount:4 fromBuffer:&value];
|
||||
else if([type isEqualToString:@"BCNT"] || [type isEqualToString:@"BZCT"]) [stream writeAmount:1 fromBuffer:(char *)(&value)+3];
|
||||
else [stream writeAmount:2 fromBuffer:(short *)(&value)+1];
|
||||
if([self countFromZero]) value += 1;
|
||||
}
|
||||
|
||||
- (BOOL)countFromZero
|
||||
{
|
||||
return [type isEqualToString:@"ZCNT"] ||
|
||||
[type isEqualToString:@"BZCT"] ||
|
||||
[type isEqualToString:@"WZCT"] ||
|
||||
[type isEqualToString:@"LZCT"];
|
||||
}
|
||||
|
||||
- (void)setValue:(unsigned long)v
|
||||
{
|
||||
value = v;
|
||||
}
|
||||
|
||||
- (unsigned long)value
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
- (void)increment
|
||||
{
|
||||
[self setValue:value+1]; // using -setValue for KVO
|
||||
}
|
||||
|
||||
- (void)decrement
|
||||
{
|
||||
if(value > 0)
|
||||
[self setValue:value-1];
|
||||
}
|
||||
|
||||
- (NSString *)stringValue
|
||||
{
|
||||
return [NSString stringWithFormat:@"%ld", value];
|
||||
}
|
||||
|
||||
- (void)setStringValue:(NSString *)str
|
||||
{
|
||||
}
|
||||
|
||||
- (BOOL)editable
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
30
NuTemplateEditor/ElementPSTR.h
Normal file
30
NuTemplateEditor/ElementPSTR.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#import "Element.h"
|
||||
|
||||
enum StringPadding
|
||||
{
|
||||
kNoPadding = 0,
|
||||
kPadToOddLength,
|
||||
kPadToEvenLength
|
||||
};
|
||||
|
||||
@interface ElementPSTR : Element
|
||||
{
|
||||
NSString *value;
|
||||
UInt32 _maxLength; // for restricted strings
|
||||
UInt32 _minLength;
|
||||
enum StringPadding _pad; // for odd- and even-padded strings
|
||||
BOOL _terminatingByte; // for C strings
|
||||
int _lengthBytes; // for Pascal strings
|
||||
int _alignment; // pads end to align on multiple of this
|
||||
}
|
||||
|
||||
- (NSString *)stringValue;
|
||||
- (void)setStringValue:(NSString *)str;
|
||||
- (void)setMaxLength:(UInt32)v;
|
||||
- (void)setMinLength:(UInt32)v;
|
||||
- (void)setPad:(enum StringPadding)v;
|
||||
- (void)setTerminatingByte:(BOOL)v;
|
||||
- (void)setLengthBytes:(int)v;
|
||||
- (void)setAlignment:(int)v;
|
||||
|
||||
@end
|
143
NuTemplateEditor/ElementPSTR.m
Normal file
143
NuTemplateEditor/ElementPSTR.m
Normal file
|
@ -0,0 +1,143 @@
|
|||
#import "ElementPSTR.h"
|
||||
|
||||
// implements PSTR, OSTR, ESTR, BSTR, WSTR, LSTR, CSTR, OCST, ECST, CHAR, TNAM
|
||||
@implementation ElementPSTR
|
||||
|
||||
- (id)initForType:(NSString *)t withLabel:(NSString *)l
|
||||
{
|
||||
self = [super initForType:t withLabel:l];
|
||||
if(!self) return nil;
|
||||
value = [@"" retain];
|
||||
if ([t isEqualToString:@"PSTR"] ||
|
||||
[t isEqualToString:@"BSTR"]) { _lengthBytes = 1; _maxLength = UINT8_MAX; _minLength = 0; _terminatingByte = NO; _pad = kNoPadding; _alignment = 0; }
|
||||
else if([t isEqualToString:@"WSTR"]) { _lengthBytes = 2; _maxLength = UINT16_MAX; _minLength = 0; _terminatingByte = NO; _pad = kNoPadding; _alignment = 0; }
|
||||
else if([t isEqualToString:@"LSTR"]) { _lengthBytes = 4; _maxLength = UINT32_MAX; _minLength = 0; _terminatingByte = NO; _pad = kNoPadding; _alignment = 0; }
|
||||
else if([t isEqualToString:@"OSTR"]) { _lengthBytes = 1; _maxLength = UINT8_MAX-1; _minLength = 0; _terminatingByte = NO; _pad = kPadToOddLength; _alignment = 0; }
|
||||
else if([t isEqualToString:@"ESTR"]) { _lengthBytes = 1; _maxLength = UINT8_MAX; _minLength = 0; _terminatingByte = NO; _pad = kPadToEvenLength; _alignment = 0; }
|
||||
else if([t isEqualToString:@"CSTR"]) { _lengthBytes = 0; _maxLength = 0; _minLength = 0; _terminatingByte = YES; _pad = kNoPadding; _alignment = 0; }
|
||||
else if([t isEqualToString:@"OCST"]) { _lengthBytes = 0; _maxLength = 0; _minLength = 0; _terminatingByte = YES; _pad = kPadToOddLength; _alignment = 0; }
|
||||
else if([t isEqualToString:@"ECST"]) { _lengthBytes = 0; _maxLength = 0; _minLength = 0; _terminatingByte = YES; _pad = kPadToEvenLength; _alignment = 0; }
|
||||
else if([t isEqualToString:@"CHAR"]) { _lengthBytes = 0; _maxLength = 1; _minLength = 1; _terminatingByte = NO; _pad = kNoPadding; _alignment = 0; }
|
||||
else if([t isEqualToString:@"TNAM"]) { _lengthBytes = 0; _maxLength = 4; _minLength = 4; _terminatingByte = NO; _pad = kNoPadding; _alignment = 0; }
|
||||
// temp until keyed values are implemented
|
||||
else if([t isEqualToString:@"KCHR"]) { _lengthBytes = 0; _maxLength = 1; _minLength = 1; _terminatingByte = NO; _pad = kNoPadding; _alignment = 0; }
|
||||
else if([t isEqualToString:@"KTYP"]) { _lengthBytes = 0; _maxLength = 4; _minLength = 4; _terminatingByte = NO; _pad = kNoPadding; _alignment = 0; }
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[value release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone*)zone
|
||||
{
|
||||
ElementPSTR *element = [super copyWithZone:zone];
|
||||
[element setStringValue:value];
|
||||
[element setMaxLength:_maxLength];
|
||||
[element setMinLength:_minLength];
|
||||
[element setPad:_pad];
|
||||
[element setTerminatingByte:_terminatingByte];
|
||||
[element setLengthBytes:_lengthBytes];
|
||||
[element setAlignment:_alignment];
|
||||
return element;
|
||||
}
|
||||
|
||||
- (void)readDataFrom:(TemplateStream *)stream
|
||||
{
|
||||
// get string length
|
||||
UInt32 length = 0;
|
||||
if(_lengthBytes > 0)
|
||||
{
|
||||
[stream readAmount:_lengthBytes toBuffer:&length];
|
||||
length >>= (4 - _lengthBytes) << 3;
|
||||
}
|
||||
if(_terminatingByte)
|
||||
length += [stream bytesToNull];
|
||||
if(_maxLength && length > _maxLength) length = _maxLength;
|
||||
if(length < _minLength) length = _minLength;
|
||||
|
||||
// read string
|
||||
void *buffer = malloc(length);
|
||||
if(_minLength) memset(buffer, 0, _minLength);
|
||||
[stream readAmount:length toBuffer:buffer];
|
||||
if([NSString instancesRespondToSelector:@selector(initWithBytesNoCopy:length:encoding:freeWhenDone:)]) // 10.3
|
||||
[self setStringValue:[[[NSString alloc] initWithBytesNoCopy:buffer length:length encoding:NSMacOSRomanStringEncoding freeWhenDone:YES] autorelease]];
|
||||
else
|
||||
{
|
||||
[self setStringValue:[[[NSString alloc] initWithBytes:buffer length:length encoding:NSMacOSRomanStringEncoding] autorelease]];
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
// skip over empty bytes
|
||||
if(_terminatingByte) [stream advanceAmount:1 pad:NO];
|
||||
if(_pad == kPadToOddLength && (length + _lengthBytes) % 2 == 0) [stream advanceAmount:1 pad:NO];
|
||||
if(_pad == kPadToEvenLength && (length + _lengthBytes) % 2 == 1) [stream advanceAmount:1 pad:NO];
|
||||
// alignment unhandled here
|
||||
}
|
||||
|
||||
- (unsigned int)sizeOnDisk
|
||||
{
|
||||
UInt32 length;
|
||||
if([value respondsToSelector:@selector(lengthOfBytesUsingEncoding:)]) // 10.4
|
||||
length = [value lengthOfBytesUsingEncoding:NSMacOSRomanStringEncoding];
|
||||
else length = [value cStringLength];
|
||||
if(_maxLength && length > _maxLength) length = _maxLength;
|
||||
if(length < _minLength) length = _minLength;
|
||||
length += _lengthBytes + (_terminatingByte? 1:0);
|
||||
if(_pad == kPadToOddLength && length % 2 == 0) length++;
|
||||
if(_pad == kPadToEvenLength && length % 2 == 1) length++;
|
||||
// don't know how to deal with alignment here
|
||||
return length;
|
||||
}
|
||||
|
||||
- (void)writeDataTo:(TemplateStream *)stream
|
||||
{
|
||||
// write string
|
||||
UInt32 length = [value length], writeLength;
|
||||
if(_maxLength && length > _maxLength) length = _maxLength;
|
||||
writeLength = length << ((4 - _lengthBytes) << 3);
|
||||
if(_lengthBytes)
|
||||
[stream writeAmount:_lengthBytes fromBuffer:&writeLength];
|
||||
if([value respondsToSelector:@selector(cStringUsingEncoding:)])
|
||||
[stream writeAmount:length fromBuffer:[value cStringUsingEncoding:NSMacOSRomanStringEncoding]];
|
||||
else [stream writeAmount:length fromBuffer:[value cString]];
|
||||
|
||||
// pad to minimum length with spaces
|
||||
if(length < _minLength)
|
||||
{
|
||||
SInt32 padAmount = _minLength - length;
|
||||
while(padAmount > 0)
|
||||
{
|
||||
UInt32 spaces = ' ';
|
||||
[stream writeAmount:(padAmount < 4)? padAmount:4 fromBuffer:&spaces];
|
||||
length += (padAmount < 4)? padAmount:4;
|
||||
padAmount -= 4;
|
||||
}
|
||||
}
|
||||
if(_terminatingByte) [stream advanceAmount:1 pad:YES];
|
||||
if(_pad == kPadToOddLength && (length + _lengthBytes + (_terminatingByte? 1:0)) % 2 == 0) [stream advanceAmount:1 pad:YES];
|
||||
if(_pad == kPadToEvenLength && (length + _lengthBytes + (_terminatingByte? 1:0)) % 2 == 1) [stream advanceAmount:1 pad:YES];
|
||||
}
|
||||
|
||||
- (NSString *)stringValue
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
- (void)setStringValue:(NSString *)str
|
||||
{
|
||||
id old = value;
|
||||
value = [str copy];
|
||||
[old release];
|
||||
}
|
||||
|
||||
- (void)setMaxLength:(UInt32)v { _maxLength = v; }
|
||||
- (void)setMinLength:(UInt32)v { _minLength = v; }
|
||||
- (void)setPad:(enum StringPadding)v { _pad = v; }
|
||||
- (void)setTerminatingByte:(BOOL)v { _terminatingByte = v; }
|
||||
- (void)setLengthBytes:(int)v { _lengthBytes = v; }
|
||||
- (void)setAlignment:(int)v { _alignment = v; }
|
||||
|
||||
@end
|
14
NuTemplateEditor/ElementUBYT.h
Normal file
14
NuTemplateEditor/ElementUBYT.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#import "Element.h"
|
||||
|
||||
@interface ElementUBYT : Element
|
||||
{
|
||||
UInt8 value;
|
||||
}
|
||||
|
||||
- (void)setValue:(UInt8)v;
|
||||
- (UInt8)value;
|
||||
|
||||
- (NSString *)stringValue;
|
||||
- (void)setStringValue:(NSString *)str;
|
||||
|
||||
@end
|
50
NuTemplateEditor/ElementUBYT.m
Normal file
50
NuTemplateEditor/ElementUBYT.m
Normal file
|
@ -0,0 +1,50 @@
|
|||
#import "ElementUBYT.h"
|
||||
|
||||
@implementation ElementUBYT
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
ElementUBYT *element = [super copyWithZone:zone];
|
||||
[element setValue:value];
|
||||
return element;
|
||||
}
|
||||
|
||||
- (void)readDataFrom:(TemplateStream *)stream
|
||||
{
|
||||
[stream readAmount:sizeof(value) toBuffer:&value];
|
||||
}
|
||||
|
||||
- (unsigned int)sizeOnDisk
|
||||
{
|
||||
return sizeof(value);
|
||||
}
|
||||
|
||||
- (void)writeDataTo:(TemplateStream *)stream
|
||||
{
|
||||
[stream writeAmount:sizeof(value) fromBuffer:&value];
|
||||
}
|
||||
|
||||
- (void)setValue:(UInt8)v
|
||||
{
|
||||
value = v;
|
||||
}
|
||||
|
||||
- (UInt8)value
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
- (NSString *)stringValue
|
||||
{
|
||||
return [NSString stringWithFormat:@"%hhu", value];
|
||||
}
|
||||
|
||||
- (void)setStringValue:(NSString *)str
|
||||
{
|
||||
char cstr[256];
|
||||
char *endPtr = cstr + 255;
|
||||
strncpy(cstr, [str cString], 255);
|
||||
value = strtoul(cstr, &endPtr, 10);
|
||||
}
|
||||
|
||||
@end
|
14
NuTemplateEditor/ElementULLG.h
Normal file
14
NuTemplateEditor/ElementULLG.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#import "Element.h"
|
||||
|
||||
@interface ElementULLG : Element
|
||||
{
|
||||
UInt64 value;
|
||||
}
|
||||
|
||||
- (void)setValue:(UInt64)v;
|
||||
- (UInt64)value;
|
||||
|
||||
- (NSString *)stringValue;
|
||||
- (void)setStringValue:(NSString *)str;
|
||||
|
||||
@end
|
50
NuTemplateEditor/ElementULLG.m
Normal file
50
NuTemplateEditor/ElementULLG.m
Normal file
|
@ -0,0 +1,50 @@
|
|||
#import "ElementULLG.h"
|
||||
|
||||
@implementation ElementULLG
|
||||
|
||||
- (id)copyWithZone:(NSZone*)zone
|
||||
{
|
||||
ElementULLG *element = [super copyWithZone:zone];
|
||||
[element setValue:value];
|
||||
return element;
|
||||
}
|
||||
|
||||
- (void)readDataFrom:(TemplateStream *)stream
|
||||
{
|
||||
[stream readAmount:sizeof(value) toBuffer:&value];
|
||||
}
|
||||
|
||||
- (unsigned int)sizeOnDisk
|
||||
{
|
||||
return sizeof(value);
|
||||
}
|
||||
|
||||
- (void)writeDataTo:(TemplateStream *)stream
|
||||
{
|
||||
[stream writeAmount:sizeof(value) fromBuffer:&value];
|
||||
}
|
||||
|
||||
- (void)setValue:(UInt64)v
|
||||
{
|
||||
value = v;
|
||||
}
|
||||
|
||||
- (UInt64)value
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
- (NSString *)stringValue
|
||||
{
|
||||
return [NSString stringWithFormat:@"%llu", value];
|
||||
}
|
||||
|
||||
- (void)setStringValue:(NSString *)str
|
||||
{
|
||||
char cstr[256];
|
||||
char *endPtr = cstr + 255;
|
||||
strncpy(cstr, [str cString], 255);
|
||||
value = strtoull(cstr, &endPtr, 10);
|
||||
}
|
||||
|
||||
@end
|
14
NuTemplateEditor/ElementULNG.h
Normal file
14
NuTemplateEditor/ElementULNG.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#import "Element.h"
|
||||
|
||||
@interface ElementULNG : Element
|
||||
{
|
||||
UInt32 value;
|
||||
}
|
||||
|
||||
- (void)setValue:(UInt32)v;
|
||||
- (UInt32)value;
|
||||
|
||||
- (NSString *)stringValue;
|
||||
- (void)setStringValue:(NSString *)str;
|
||||
|
||||
@end
|
50
NuTemplateEditor/ElementULNG.m
Normal file
50
NuTemplateEditor/ElementULNG.m
Normal file
|
@ -0,0 +1,50 @@
|
|||
#import "ElementULNG.h"
|
||||
|
||||
@implementation ElementULNG
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
ElementULNG *element = [super copyWithZone:zone];
|
||||
[element setValue:value];
|
||||
return element;
|
||||
}
|
||||
|
||||
- (void)readDataFrom:(TemplateStream *)stream
|
||||
{
|
||||
[stream readAmount:sizeof(value) toBuffer:&value];
|
||||
}
|
||||
|
||||
- (unsigned int)sizeOnDisk
|
||||
{
|
||||
return sizeof(value);
|
||||
}
|
||||
|
||||
- (void)writeDataTo:(TemplateStream *)stream
|
||||
{
|
||||
[stream writeAmount:sizeof(value) fromBuffer:&value];
|
||||
}
|
||||
|
||||
- (void)setValue:(UInt32)v
|
||||
{
|
||||
value = v;
|
||||
}
|
||||
|
||||
- (UInt32)value
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
- (NSString *)stringValue
|
||||
{
|
||||
return [NSString stringWithFormat:@"%lu", value];
|
||||
}
|
||||
|
||||
- (void)setStringValue:(NSString *)str
|
||||
{
|
||||
char cstr[256];
|
||||
char *endPtr = cstr + 255;
|
||||
strncpy(cstr, [str cString], 255);
|
||||
value = strtoul(cstr, &endPtr, 10);
|
||||
}
|
||||
|
||||
@end
|
14
NuTemplateEditor/ElementUWRD.h
Normal file
14
NuTemplateEditor/ElementUWRD.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#import "Element.h"
|
||||
|
||||
@interface ElementUWRD : Element
|
||||
{
|
||||
UInt16 value;
|
||||
}
|
||||
|
||||
- (void)setValue:(UInt16)v;
|
||||
- (UInt16)value;
|
||||
|
||||
- (NSString *)stringValue;
|
||||
- (void)setStringValue:(NSString *)str;
|
||||
|
||||
@end
|
50
NuTemplateEditor/ElementUWRD.m
Normal file
50
NuTemplateEditor/ElementUWRD.m
Normal file
|
@ -0,0 +1,50 @@
|
|||
#import "ElementUWRD.h"
|
||||
|
||||
@implementation ElementUWRD
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
ElementUWRD *element = [super copyWithZone:zone];
|
||||
[element setValue:value];
|
||||
return element;
|
||||
}
|
||||
|
||||
- (void)readDataFrom:(TemplateStream *)stream
|
||||
{
|
||||
[stream readAmount:sizeof(value) toBuffer:&value];
|
||||
}
|
||||
|
||||
- (unsigned int)sizeOnDisk
|
||||
{
|
||||
return sizeof(value);
|
||||
}
|
||||
|
||||
- (void)writeDataTo:(TemplateStream *)stream
|
||||
{
|
||||
[stream writeAmount:sizeof(value) fromBuffer:&value];
|
||||
}
|
||||
|
||||
- (void)setValue:(UInt16)v
|
||||
{
|
||||
value = v;
|
||||
}
|
||||
|
||||
- (UInt16)value
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
- (NSString*)stringValue
|
||||
{
|
||||
return [NSString stringWithFormat:@"%hu", value];
|
||||
}
|
||||
|
||||
- (void)setStringValue:(NSString *)str
|
||||
{
|
||||
char cstr[256];
|
||||
char *endPtr = cstr + 255;
|
||||
strncpy(cstr, [str cString], 255);
|
||||
value = strtoul(cstr, &endPtr, 10);
|
||||
}
|
||||
|
||||
@end
|
BIN
NuTemplateEditor/English.lproj/NuTemplateWindow.nib/objects.nib
generated
Normal file
BIN
NuTemplateEditor/English.lproj/NuTemplateWindow.nib/objects.nib
generated
Normal file
Binary file not shown.
33
NuTemplateEditor/Info.plist
Normal file
33
NuTemplateEditor/Info.plist
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>Template Editor</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.nickshanks.resknife.templateeditor</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>ResK</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.1 b2</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>TemplateWindowController</string>
|
||||
<key>RKSupportedTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>IsResKnifeDefaultForType</key>
|
||||
<string>YES</string>
|
||||
<key>RKTypeName</key>
|
||||
<string>Template Editor</string>
|
||||
<key>RKTypeRole</key>
|
||||
<string>Editor</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
BIN
NuTemplateEditor/Localizable.strings
Normal file
BIN
NuTemplateEditor/Localizable.strings
Normal file
Binary file not shown.
|
@ -9,11 +9,11 @@ lists, there is a subclass GroupElement from which you can instead subclass to
|
|||
have some of the work done for you.
|
||||
|
||||
When opening a resource, the template editor first creates a TemplateStream for the template
|
||||
resource and calls readOneObject: on it until it runs out of data, instantiating a hierarchy
|
||||
resource and calls readOneObject:on it until it runs out of data, instantiating a hierarchy
|
||||
of Element subclasses for based on the template.
|
||||
|
||||
After that, it creates a TemplateStream for the resource and loops over the template object
|
||||
hierarchy, creating a copy of each item, and then calling readDataFrom:containingArray: on
|
||||
hierarchy, creating a copy of each item, and then calling readDataFrom:containingArray:on
|
||||
the copy, which in turn reads data from the TemplateStream and stores it in its instance
|
||||
variables. For this to work, subclasses of Element *must* implement the NSCopying
|
||||
protocol.
|
||||
|
@ -28,10 +28,10 @@ resource and passed to all template fields (the copies with the resource data, n
|
|||
pre-parsed template hierarchy), via writeDataTo:, which is where they should write their
|
||||
data to the stream. Before that, sizeOnDisk is called on each Element to
|
||||
calculate the new size of the resource before the actual process of writing them out.
|
||||
This size must include the size of all of their sub-items, and writeDataTo: must call
|
||||
This size must include the size of all of their sub-items, and writeDataTo:must call
|
||||
these sub items if they are to be written to disk.
|
||||
|
||||
SPECIAL CASE: LISTS
|
||||
SPECIAL CASE:LISTS
|
||||
|
||||
When the editor encounters an LSTB element, the LSTB element is called upon to parse its
|
||||
"sub-elements" (the items that make up one list item). The LSTB element reads all elements
|
BIN
NuTemplateEditor/Resources/DisplayTMPL.png
Normal file
BIN
NuTemplateEditor/Resources/DisplayTMPL.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 274 B |
BIN
NuTemplateEditor/TMPLs.rsrc
Normal file
BIN
NuTemplateEditor/TMPLs.rsrc
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
36
NuTemplateEditor/TemplateStream.h
Normal file
36
NuTemplateEditor/TemplateStream.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class Element;
|
||||
@interface TemplateStream : NSObject
|
||||
{
|
||||
char *data;
|
||||
unsigned int bytesToGo;
|
||||
NSMutableArray *counterStack;
|
||||
NSMutableArray *keyStack;
|
||||
}
|
||||
|
||||
+ (id)streamWithBytes:(char *)d length:(unsigned int)l;
|
||||
+ (id)substreamWithStream:(TemplateStream *)s length:(unsigned int)l;
|
||||
|
||||
- (id)initStreamWithBytes:(char *)d length:(unsigned int)l;
|
||||
- (id)initWithStream:(TemplateStream *)s length:(unsigned int)l;
|
||||
|
||||
- (char *)data;
|
||||
- (unsigned int)bytesToGo;
|
||||
- (void)setBytesToGo:(unsigned int)b;
|
||||
- (Element *)counter;
|
||||
- (void)pushCounter:(Element *)c;
|
||||
- (void)popCounter;
|
||||
- (Element *)key;
|
||||
- (void)pushKey:(Element *)k;
|
||||
- (void)popKey;
|
||||
|
||||
- (Element *)readOneElement; // For parsing of 'TMPL' resource as template.
|
||||
- (unsigned int)bytesToNull;
|
||||
- (void)advanceAmount:(unsigned int)l pad:(BOOL)pad; // advance r/w pointer and optionally write padding bytes
|
||||
- (void)peekAmount:(unsigned int)l toBuffer:(void *)buffer; // read bytes without advancing pointer
|
||||
- (void)readAmount:(unsigned int)l toBuffer:(void *)buffer; // stream reading
|
||||
- (void)writeAmount:(unsigned int)l fromBuffer:(const void *)buffer; // stream writing
|
||||
- (NSMutableDictionary *)fieldRegistry;
|
||||
|
||||
@end
|
313
NuTemplateEditor/TemplateStream.m
Normal file
313
NuTemplateEditor/TemplateStream.m
Normal file
|
@ -0,0 +1,313 @@
|
|||
#import "TemplateStream.h"
|
||||
#import "Element.h"
|
||||
#import "ElementOCNT.h" // for tracking current counter
|
||||
#import "ElementHEXD.h" // for errors
|
||||
|
||||
#import "ElementDBYT.h"
|
||||
#import "ElementDWRD.h"
|
||||
#import "ElementDLNG.h"
|
||||
#import "ElementDLLG.h"
|
||||
#import "ElementUBYT.h"
|
||||
#import "ElementUWRD.h"
|
||||
#import "ElementULNG.h"
|
||||
#import "ElementULLG.h"
|
||||
#import "ElementFIXD.h"
|
||||
#import "ElementFRAC.h"
|
||||
#import "ElementFBYT.h"
|
||||
#import "ElementPSTR.h"
|
||||
//#import "ElementHEXD.h"
|
||||
#import "ElementDATE.h"
|
||||
//#import "ElementOCNT.h"
|
||||
#import "ElementLSTB.h"
|
||||
#import "ElementLSTC.h"
|
||||
#import "ElementLSTE.h"
|
||||
#import "ElementKEYB.h"
|
||||
|
||||
@implementation TemplateStream
|
||||
|
||||
+ (id)streamWithBytes:(char *)d length:(unsigned int)l
|
||||
{
|
||||
return [[[self alloc] autorelease] initStreamWithBytes:d length:l];
|
||||
}
|
||||
|
||||
+ (id)substreamWithStream:(TemplateStream *)s length:(unsigned int)l
|
||||
{
|
||||
return [[[self alloc] autorelease] initWithStream:s length:l];
|
||||
}
|
||||
|
||||
- (id)initStreamWithBytes:(char *)d length:(unsigned int)l
|
||||
{
|
||||
self = [super init];
|
||||
if(!self) return nil;
|
||||
data = d;
|
||||
bytesToGo = l;
|
||||
counterStack = [[NSMutableArray alloc] init];
|
||||
keyStack = [[NSMutableArray alloc] init];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithStream:(TemplateStream *)s length:(unsigned int)l
|
||||
{
|
||||
return [self initStreamWithBytes:[s data] length:MIN(l, [s bytesToGo])];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[counterStack release];
|
||||
[keyStack release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (char *)data
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
- (unsigned int)bytesToGo
|
||||
{
|
||||
return bytesToGo;
|
||||
}
|
||||
|
||||
- (void)setBytesToGo:(unsigned int)b
|
||||
{
|
||||
bytesToGo = b;
|
||||
}
|
||||
|
||||
- (unsigned int)bytesToNull
|
||||
{
|
||||
unsigned int dist = 0;
|
||||
while(dist < bytesToGo)
|
||||
{
|
||||
if(*(char *)(data+dist) == 0x00)
|
||||
return dist;
|
||||
dist++;
|
||||
}
|
||||
return bytesToGo;
|
||||
}
|
||||
|
||||
- (Element *)counter
|
||||
{
|
||||
return [counterStack lastObject];
|
||||
}
|
||||
|
||||
- (void)pushCounter:(Element *)c
|
||||
{
|
||||
[counterStack addObject:c];
|
||||
}
|
||||
|
||||
- (void)popCounter
|
||||
{
|
||||
[counterStack removeLastObject];
|
||||
}
|
||||
|
||||
- (Element *)key
|
||||
{
|
||||
NSLog(@"Getting last key of stack: %@", keyStack);
|
||||
return [counterStack lastObject];
|
||||
}
|
||||
|
||||
- (void)pushKey:(Element *)k
|
||||
{
|
||||
[keyStack addObject:k];
|
||||
NSLog(@"Pushed key to stack: %@", keyStack);
|
||||
}
|
||||
|
||||
- (void)popKey
|
||||
{
|
||||
NSLog(@"Popping key from stack: %@", keyStack);
|
||||
[keyStack removeLastObject];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (Element *)readOneElement
|
||||
{
|
||||
// check where pointer will be AFTER having loaded this element
|
||||
NSString *type = nil, *label = nil;
|
||||
if(*data + 5 <= bytesToGo)
|
||||
{
|
||||
bytesToGo -= *data + 5;
|
||||
label = [[[NSString alloc] initWithBytes:data+1 length:*data encoding:NSMacOSRomanStringEncoding] autorelease];
|
||||
data += *data +1;
|
||||
type = [[[NSString alloc] initWithBytes:data length:4 encoding:NSMacOSRomanStringEncoding] autorelease];
|
||||
data += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytesToGo = 0;
|
||||
NSLog(@"Corrupt TMPL resource: not enough data. Dumping remaining resource as hex.");
|
||||
return [ElementHEXD elementForType:@"HEXD" withLabel:NSLocalizedString(@"Error: Hex Dump", nil)];
|
||||
}
|
||||
|
||||
// create element class
|
||||
Class class = [[self fieldRegistry] objectForKey:type];
|
||||
if(class)
|
||||
{
|
||||
Element *element = (Element *) [class elementForType:type withLabel:label];
|
||||
[element readSubElementsFrom:self];
|
||||
return element;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytesToGo = 0;
|
||||
NSLog(@"Class not found for template element type '%@'. Dumping remaining resource as hex.", type);
|
||||
return [ElementHEXD elementForType:@"HEXD" withLabel:NSLocalizedString(@"Error: Hex Dump", nil)];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)advanceAmount:(unsigned int)l pad:(BOOL)pad
|
||||
{
|
||||
if(l > bytesToGo) l = bytesToGo;
|
||||
if(l > 0)
|
||||
{
|
||||
if(pad) memset(data, 0, l);
|
||||
data += l;
|
||||
bytesToGo -= l;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)peekAmount:(unsigned int)l toBuffer:(void *)buffer
|
||||
{
|
||||
if(l > bytesToGo) l = bytesToGo;
|
||||
if(l > 0) memmove(buffer, data, l);
|
||||
}
|
||||
|
||||
- (void)readAmount:(unsigned int)l toBuffer:(void *)buffer
|
||||
{
|
||||
if(l > bytesToGo) l = bytesToGo;
|
||||
if(l > 0)
|
||||
{
|
||||
memmove(buffer, data, l);
|
||||
data += l;
|
||||
bytesToGo -= l;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)writeAmount:(unsigned int)l fromBuffer:(const void *)buffer
|
||||
{
|
||||
if(l > bytesToGo) l = bytesToGo;
|
||||
if(l > 0)
|
||||
{
|
||||
memmove(data, buffer, l);
|
||||
data += l;
|
||||
bytesToGo -= l;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Misc
|
||||
|
||||
- (NSMutableDictionary *)fieldRegistry
|
||||
{
|
||||
static NSMutableDictionary *registry = nil;
|
||||
if(!registry)
|
||||
{
|
||||
registry = [[NSMutableDictionary alloc] init];
|
||||
|
||||
// integers
|
||||
[registry setObject:[ElementDBYT class] forKey:@"DBYT"]; // signed ints
|
||||
[registry setObject:[ElementDWRD class] forKey:@"DWRD"];
|
||||
[registry setObject:[ElementDLNG class] forKey:@"DLNG"];
|
||||
[registry setObject:[ElementDLLG class] forKey:@"DLLG"];
|
||||
[registry setObject:[ElementUBYT class] forKey:@"UBYT"]; // unsigned ints
|
||||
[registry setObject:[ElementUWRD class] forKey:@"UWRD"];
|
||||
[registry setObject:[ElementULNG class] forKey:@"ULNG"];
|
||||
[registry setObject:[ElementULLG class] forKey:@"ULLG"];
|
||||
[registry setObject:[ElementFBYT class] forKey:@"FBYT"]; // filler ints
|
||||
[registry setObject:[ElementFBYT class] forKey:@"FWRD"];
|
||||
[registry setObject:[ElementFBYT class] forKey:@"FLNG"];
|
||||
[registry setObject:[ElementFBYT class] forKey:@"FLLG"];
|
||||
|
||||
// fractions
|
||||
[registry setObject:[ElementFIXD class] forKey:@"FIXD"]; // 16.16 fixed fraction
|
||||
[registry setObject:[ElementFRAC class] forKey:@"FRAC"]; // 2.30 fixed fraction
|
||||
|
||||
// strings
|
||||
[registry setObject:[ElementPSTR class] forKey:@"PSTR"];
|
||||
[registry setObject:[ElementPSTR class] forKey:@"BSTR"];
|
||||
[registry setObject:[ElementPSTR class] forKey:@"WSTR"];
|
||||
[registry setObject:[ElementPSTR class] forKey:@"LSTR"];
|
||||
[registry setObject:[ElementPSTR class] forKey:@"OSTR"];
|
||||
[registry setObject:[ElementPSTR class] forKey:@"ESTR"];
|
||||
[registry setObject:[ElementPSTR class] forKey:@"CSTR"];
|
||||
[registry setObject:[ElementPSTR class] forKey:@"OCST"];
|
||||
[registry setObject:[ElementPSTR class] forKey:@"ECST"];
|
||||
[registry setObject:[ElementPSTR class] forKey:@"CHAR"];
|
||||
[registry setObject:[ElementPSTR class] forKey:@"TNAM"];
|
||||
|
||||
// hex dumps
|
||||
[registry setObject:[ElementHEXD class] forKey:@"HEXD"];
|
||||
|
||||
// list counters
|
||||
[registry setObject:[ElementOCNT class] forKey:@"OCNT"];
|
||||
[registry setObject:[ElementOCNT class] forKey:@"ZCNT"];
|
||||
[registry setObject:[ElementOCNT class] forKey:@"BCNT"];
|
||||
[registry setObject:[ElementOCNT class] forKey:@"BZCT"];
|
||||
[registry setObject:[ElementOCNT class] forKey:@"WCNT"];
|
||||
[registry setObject:[ElementOCNT class] forKey:@"WZCT"];
|
||||
[registry setObject:[ElementOCNT class] forKey:@"LCNT"];
|
||||
[registry setObject:[ElementOCNT class] forKey:@"LZCT"];
|
||||
// list begin/end
|
||||
[registry setObject:[ElementLSTC class] forKey:@"LSTC"];
|
||||
[registry setObject:[ElementLSTB class] forKey:@"LSTB"];
|
||||
[registry setObject:[ElementLSTB class] forKey:@"LSTZ"];
|
||||
[registry setObject:[ElementLSTE class] forKey:@"LSTE"];
|
||||
// key begin/end
|
||||
[registry setObject:[ElementKEYB class] forKey:@"KEYB"];
|
||||
[registry setObject:[ElementKEYE class] forKey:@"KEYE"];
|
||||
|
||||
// dates
|
||||
[registry setObject:[ElementDATE class] forKey:@"DATE"]; // 4-byte date (seconds since 1 Jan 1904)
|
||||
[registry setObject:[ElementDATE class] forKey:@"MDAT"];
|
||||
|
||||
// and some faked ones just to increase compatibility (these are marked 'x' in the docs)
|
||||
[registry setObject:[ElementUBYT class] forKey:@"HBYT"]; // hex byte/word/long
|
||||
[registry setObject:[ElementUWRD class] forKey:@"HWRD"];
|
||||
[registry setObject:[ElementULNG class] forKey:@"HLNG"];
|
||||
[registry setObject:[ElementULLG class] forKey:@"HLLG"];
|
||||
[registry setObject:[ElementKBYT class] forKey:@"KBYT"]; // signed keys
|
||||
[registry setObject:[ElementKWRD class] forKey:@"KWRD"];
|
||||
[registry setObject:[ElementKLNG class] forKey:@"KLNG"];
|
||||
[registry setObject:[ElementDLLG class] forKey:@"KLLG"];
|
||||
[registry setObject:[ElementUBYT class] forKey:@"KUBT"]; // unsigned keys
|
||||
[registry setObject:[ElementUWRD class] forKey:@"KUWD"];
|
||||
[registry setObject:[ElementULNG class] forKey:@"KULG"];
|
||||
[registry setObject:[ElementULLG class] forKey:@"KULL"];
|
||||
[registry setObject:[ElementUBYT class] forKey:@"KHBT"]; // hex keys
|
||||
[registry setObject:[ElementUWRD class] forKey:@"KHWD"];
|
||||
[registry setObject:[ElementULNG class] forKey:@"KHLG"];
|
||||
[registry setObject:[ElementULLG class] forKey:@"KHLL"];
|
||||
[registry setObject:[ElementPSTR class] forKey:@"KCHR"]; // keyed MacRoman values
|
||||
[registry setObject:[ElementPSTR class] forKey:@"KTYP"];
|
||||
[registry setObject:[ElementFBYT class] forKey:@"KRID"]; // key on ID of the resource
|
||||
[registry setObject:[ElementUWRD class] forKey:@"BOOL"]; // true = 256; false = 0
|
||||
[registry setObject:[ElementUBYT class] forKey:@"BFLG"]; // binary flag the size of a byte/word/long
|
||||
[registry setObject:[ElementUWRD class] forKey:@"WFLG"];
|
||||
[registry setObject:[ElementULNG class] forKey:@"LFLG"];
|
||||
[registry setObject:[ElementDWRD class] forKey:@"RSID"]; // resouce id (signed word)
|
||||
[registry setObject:[ElementULNG class] forKey:@"REAL"]; // single precision float
|
||||
[registry setObject:[ElementULLG class] forKey:@"DOUB"]; // double precision float
|
||||
[registry setObject:[ElementUWRD class] forKey:@"SFRC"]; // 0.16 fixed fraction
|
||||
[registry setObject:[ElementUWRD class] forKey:@"FXYZ"]; // 1.15 fixed fraction
|
||||
[registry setObject:[ElementUWRD class] forKey:@"FWID"]; // 4.12 fixed fraction
|
||||
[registry setObject:[ElementFBYT class] forKey:@"CASE"];
|
||||
[registry setObject:[ElementFBYT class] forKey:@"TITL"]; // resource title (e.g. utxt would have "Unicode Text"; must be first element of template, and not anywhere else)
|
||||
[registry setObject:[ElementFBYT class] forKey:@"CMNT"];
|
||||
[registry setObject:[ElementFBYT class] forKey:@"DVDR"];
|
||||
[registry setObject:[ElementULLG class] forKey:@"LLDT"]; // 8-byte date (LongDateTime; seconds since 1 Jan 1904)
|
||||
[registry setObject:[ElementDBYT class] forKey:@"STYL"]; // QuickDraw font style
|
||||
[registry setObject:[ElementULNG class] forKey:@"PNT "]; // QuickDraw point
|
||||
[registry setObject:[ElementULLG class] forKey:@"RECT"]; // QuickDraw rect
|
||||
[registry setObject:[ElementDWRD class] forKey:@"SCPC"]; // MacOS script code (ScriptCode)
|
||||
[registry setObject:[ElementDWRD class] forKey:@"LNGC"]; // MacOS language code (LangCode)
|
||||
[registry setObject:[ElementDWRD class] forKey:@"RGNC"]; // MacOS region code (RegionCode)
|
||||
|
||||
// unhandled types at present, see file:///Users/nicholas/Sites/resknife.sf.net/resorcerer_comparison.html
|
||||
// BBIT, BBnn, FBIT, FBnn, WBIT, WBnn
|
||||
// Pnnn, Cnnn, Hnnn, Fnnn, HEXD
|
||||
// AWRD, ALNG (not so easy, element needs to know how much data preceeds it in the stream)
|
||||
}
|
||||
return registry;
|
||||
}
|
||||
|
||||
@end
|
53
NuTemplateEditor/TemplateWindowController.h
Normal file
53
NuTemplateEditor/TemplateWindowController.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/* =============================================================================
|
||||
PROJECT: ResKnife
|
||||
FILE: TemplateWindowController.h
|
||||
|
||||
PURPOSE: This is the main class of our template editor. Every
|
||||
resource editor's main class implements the
|
||||
ResKnifePluginProtocol. Every editor should implement
|
||||
initWithResource:. Only implement initWithResources:if you feel
|
||||
like writing a template editor.
|
||||
|
||||
Note that your plugin is responsible for committing suicide
|
||||
after its window has been closed. If you subclass it from
|
||||
NSWindowController, the controller will take care of that
|
||||
for you, according to a guy named Doug.
|
||||
|
||||
AUTHORS: M. Uli Kusterer, witness(at)zathras.de, (c) 2003.
|
||||
|
||||
REVISIONS:
|
||||
2003-07-31 UK Created.
|
||||
========================================================================== */
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "ResKnifePluginProtocol.h"
|
||||
#import "ResKnifeResourceProtocol.h"
|
||||
|
||||
@interface TemplateWindowController : NSWindowController <ResKnifeTemplatePluginProtocol>
|
||||
{
|
||||
IBOutlet NSOutlineView *displayList; // template display (debug only).
|
||||
IBOutlet NSOutlineView *dataList; // Data display.
|
||||
IBOutlet NSDrawer *tmplDrawer;
|
||||
NSMutableDictionary *toolbarItems;
|
||||
NSMutableArray *templateStructure; // Pre-parsed form of our template.
|
||||
NSMutableArray *resourceStructure; // Parsed form of our resource.
|
||||
id <ResKnifeResourceProtocol> resource; // The resource we operate on.
|
||||
id <ResKnifeResourceProtocol> backup; // The original resource.
|
||||
BOOL liveEdit;
|
||||
}
|
||||
|
||||
- (void)setupToolbar;
|
||||
- (void)readTemplate:(id <ResKnifeResourceProtocol>)tmplRes;
|
||||
- (void)loadResource;
|
||||
- (IBAction)saveResource:(id)sender;
|
||||
- (IBAction)revertResource:(id)sender;
|
||||
- (IBAction)createListEntry:(id)sender;
|
||||
- (IBAction)cut:(id)sender;
|
||||
- (IBAction)copy:(id)sender;
|
||||
- (IBAction)paste:(id)sender;
|
||||
- (IBAction)clear:(id)sender;
|
||||
|
||||
@end
|
||||
|
||||
@interface NTOutlineView : NSOutlineView
|
||||
@end
|
461
NuTemplateEditor/TemplateWindowController.mm
Normal file
461
NuTemplateEditor/TemplateWindowController.mm
Normal file
|
@ -0,0 +1,461 @@
|
|||
#import "TemplateWindowController.h"
|
||||
#import "TemplateStream.h"
|
||||
#import "Element.h"
|
||||
#import "ElementOCNT.h"
|
||||
#import "ElementLSTE.h"
|
||||
// and ones for keyed fields
|
||||
#import "ElementDBYT.h"
|
||||
#import "ElementDWRD.h"
|
||||
#import "ElementDLNG.h"
|
||||
|
||||
#import "NSOutlineView-SelectedItems.h"
|
||||
|
||||
@implementation TemplateWindowController
|
||||
|
||||
- (id)initWithResource:(id <ResKnifeResourceProtocol>)newResource
|
||||
{
|
||||
return [self initWithResources:newResource, nil];
|
||||
}
|
||||
|
||||
- (id)initWithResources:(id <ResKnifeResourceProtocol>)newResource, ...
|
||||
{
|
||||
id tmplResource;
|
||||
va_list resourceList;
|
||||
|
||||
va_start(resourceList, newResource);
|
||||
self = [self initWithWindowNibName:@"TemplateWindow"];
|
||||
if(!self)
|
||||
{
|
||||
va_end(resourceList);
|
||||
return nil;
|
||||
}
|
||||
|
||||
toolbarItems = [[NSMutableDictionary alloc] init];
|
||||
// undoManager = [[NSUndoManager alloc] init];
|
||||
liveEdit = NO;
|
||||
if(liveEdit)
|
||||
{
|
||||
resource = [(id)newResource retain]; // resource to work on
|
||||
backup = [(NSObject *)resource copy]; // for reverting only
|
||||
}
|
||||
else
|
||||
{
|
||||
backup = [(id)newResource retain]; // actual resource to change when saving data
|
||||
resource = [(NSObject *)backup copy]; // resource to work on
|
||||
}
|
||||
templateStructure = [[NSMutableArray alloc] init];
|
||||
resourceStructure = [[NSMutableArray alloc] init];
|
||||
|
||||
tmplResource = va_arg(resourceList, id);
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(templateDataDidChange:) name:ResourceDataDidChangeNotification object:tmplResource];
|
||||
[self readTemplate:tmplResource]; // reads (but doesn't retain) the template for this resource (TMPL resource with name equal to the passed resource's type)
|
||||
|
||||
while(tmplResource = va_arg(resourceList, id))
|
||||
NSLog(@"Too many params passed to -initWithResources:%@", [tmplResource description]);
|
||||
va_end(resourceList);
|
||||
|
||||
// load the window from the nib
|
||||
[self setShouldCascadeWindows:YES];
|
||||
[self window];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
[toolbarItems release];
|
||||
[templateStructure release];
|
||||
[resourceStructure release];
|
||||
[(id)resource release];
|
||||
[(id)backup release];
|
||||
[super dealloc];
|
||||
}
|
||||
/*
|
||||
- (void)windowControllerDidLoadNib:(NSWindowController *)controller
|
||||
{
|
||||
[super windowControllerDidLoadNib:controller];
|
||||
[self setupToolbar:controller];
|
||||
}
|
||||
*/
|
||||
- (void)windowDidLoad
|
||||
{
|
||||
[super windowDidLoad];
|
||||
[self setupToolbar];
|
||||
[self loadResource];
|
||||
if(liveEdit) [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceDataDidChange:) name:ResourceDataDidChangeNotification object:resource];
|
||||
else [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceDataDidChange:) name:ResourceDataDidChangeNotification object:backup];
|
||||
[[self window] setTitle:[resource defaultWindowTitle]];
|
||||
[self showWindow:self];
|
||||
[displayList reloadData];
|
||||
}
|
||||
|
||||
- (void)templateDataDidChange:(NSNotification *)notification
|
||||
{
|
||||
[templateStructure removeAllObjects];
|
||||
[self readTemplate:[notification object]];
|
||||
if([self isWindowLoaded])
|
||||
[self loadResource];
|
||||
}
|
||||
|
||||
- (void)resourceDataDidChange:(NSNotification *)notification
|
||||
{
|
||||
if(!liveEdit)
|
||||
// bug: should display alert asking if you want to replace data in this editor or reassert this data, revoking the other editor's changes
|
||||
[resource setData:[[backup data] copy]];
|
||||
[self loadResource];
|
||||
}
|
||||
|
||||
- (void)loadResource
|
||||
{
|
||||
// create new stream
|
||||
TemplateStream *stream = [TemplateStream streamWithBytes:(char *)[[resource data] bytes] length:[[resource data] length]];
|
||||
|
||||
// loop through template cloning its elements
|
||||
[resourceStructure removeAllObjects];
|
||||
NSEnumerator *enumerator = [templateStructure objectEnumerator];
|
||||
while(Element *element = [enumerator nextObject])
|
||||
{
|
||||
Element *clone = [[element copy] autorelease]; // copy the template object.
|
||||
NSLog(@"clone = %@; resourceStructure = %@", clone, resourceStructure);
|
||||
[resourceStructure addObject:clone]; // add it to our parsed resource data list. Do this right away so the element can append other items should it desire to.
|
||||
[clone setParentArray:resourceStructure]; // the parent for these is the root level resourceStructure object
|
||||
Class cc = [clone class];
|
||||
|
||||
BOOL pushedCounter = NO;
|
||||
BOOL pushedKey = NO;
|
||||
if(cc == [ElementOCNT class])
|
||||
{ [stream pushCounter:clone]; pushedCounter = YES; }
|
||||
if(cc == [ElementKBYT class] ||
|
||||
cc == [ElementKWRD class] ||
|
||||
cc == [ElementKLNG class] )
|
||||
{ [stream pushKey:clone]; pushedKey = YES; }
|
||||
[clone readDataFrom:stream]; // fill it with resource data.
|
||||
if(cc == [ElementLSTE class] && pushedCounter)
|
||||
[stream popCounter];
|
||||
// if(cc == [ElementKEYE class] && pushedKey)
|
||||
// [stream popKey];
|
||||
}
|
||||
|
||||
// reload the view
|
||||
[dataList reloadData];
|
||||
}
|
||||
|
||||
- (BOOL)windowShouldClose:(id)sender
|
||||
{
|
||||
[[self window] makeFirstResponder:dataList];
|
||||
[dataList abortEditing];
|
||||
|
||||
if([[self window] isDocumentEdited])
|
||||
{
|
||||
NSBeginAlertSheet(@"Do you want to keep the changes you made to this resource?", @"Keep", @"Don't Keep", @"Cancel", sender, self, @selector(saveSheetDidClose:returnCode:contextInfo:), nil, nil, @"Your changes cannot be saved later if you don't keep them.");
|
||||
return NO;
|
||||
}
|
||||
else return YES;
|
||||
}
|
||||
|
||||
- (void)saveSheetDidClose:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
|
||||
{
|
||||
switch(returnCode)
|
||||
{
|
||||
case NSAlertDefaultReturn: // keep
|
||||
[self saveResource:nil];
|
||||
[[self window] close];
|
||||
break;
|
||||
|
||||
case NSAlertAlternateReturn: // don't keep
|
||||
[[self window] close];
|
||||
break;
|
||||
|
||||
case NSAlertOtherReturn: // cancel
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)saveResource:(id)sender
|
||||
{
|
||||
// get size of resource by summing size of all fields
|
||||
unsigned int size = 0;
|
||||
NSEnumerator *enumerator = [resourceStructure objectEnumerator];
|
||||
while(Element *element = [enumerator nextObject])
|
||||
size += [element sizeOnDisk];
|
||||
|
||||
// create data and stream
|
||||
NSMutableData *newData = [NSMutableData dataWithLength:size];
|
||||
TemplateStream *stream = [TemplateStream streamWithBytes:(char *)[newData bytes] length:size];
|
||||
|
||||
// write bytes into new data object
|
||||
enumerator = [resourceStructure objectEnumerator];
|
||||
while(Element *element = [enumerator nextObject])
|
||||
[element writeDataTo:stream];
|
||||
|
||||
// send the new resource data to ResKnife
|
||||
if(liveEdit)
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:ResourceDataDidChangeNotification object:resource];
|
||||
[resource setData:newData];
|
||||
[backup setData:[newData copy]];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceDataDidChange:) name:ResourceDataDidChangeNotification object:resource];
|
||||
}
|
||||
else
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:ResourceDataDidChangeNotification object:backup];
|
||||
[resource setData:newData];
|
||||
[backup setData:[newData copy]];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceDataDidChange:) name:ResourceDataDidChangeNotification object:backup];
|
||||
[self setDocumentEdited:NO];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)revertResource:(id)sender
|
||||
{
|
||||
[resource setData:[[backup data] copy]];
|
||||
}
|
||||
|
||||
- (void)readTemplate:(id<ResKnifeResourceProtocol>)tmplRes
|
||||
{
|
||||
char *data = (char*) [[tmplRes data] bytes];
|
||||
unsigned long bytesToGo = [[tmplRes data] length];
|
||||
TemplateStream *stream = [TemplateStream streamWithBytes:data length:bytesToGo];
|
||||
|
||||
// read new fields from the template and add them to our list
|
||||
while([stream bytesToGo] > 0)
|
||||
{
|
||||
Element *element = [stream readOneElement];
|
||||
if(element)
|
||||
{
|
||||
[element setIsTMPL:YES]; // for debugging
|
||||
[templateStructure addObject:element];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"Error reading template stream, aborting.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[displayList reloadData];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Table Management
|
||||
|
||||
- (id)outlineView:(NSOutlineView*)outlineView child:(int)index ofItem:(id)item
|
||||
{
|
||||
if((item == nil) && (outlineView == displayList))
|
||||
return [templateStructure objectAtIndex:index];
|
||||
else if((item == nil) && (outlineView == dataList))
|
||||
return [resourceStructure objectAtIndex:index];
|
||||
else return [item subElementAtIndex:index];
|
||||
}
|
||||
|
||||
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
|
||||
{
|
||||
return ([item subElementCount] > 0);
|
||||
}
|
||||
|
||||
- (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
|
||||
{
|
||||
if((item == nil) && (outlineView == displayList))
|
||||
return [templateStructure count];
|
||||
else if((item == nil) && (outlineView == dataList))
|
||||
return [resourceStructure count];
|
||||
else return [item subElementCount];
|
||||
}
|
||||
|
||||
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
|
||||
{
|
||||
return [item valueForKey:[tableColumn identifier]];
|
||||
}
|
||||
|
||||
- (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
|
||||
{
|
||||
id old = [item valueForKey:[tableColumn identifier]];
|
||||
if([(Element *)item editable] && ![old isEqual:object])
|
||||
{
|
||||
// [[self undoManager] registerUndoWithTarget:item selector:@selector(setStringValue:) object:old];
|
||||
// [[self undoManager] setActionName:NSLocalizedString(@"Changes", nil)];
|
||||
[item setValue:object forKey:[tableColumn identifier]];
|
||||
if(!liveEdit) [self setDocumentEdited:YES];
|
||||
|
||||
// remove self to avoid reloading the resource
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:ResourceDataDidChangeNotification object:resource];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceDataDidChangeNotification object:resource];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceDataDidChange:) name:ResourceDataDidChangeNotification object:resource];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
|
||||
{
|
||||
return [(Element *)item editable];
|
||||
}
|
||||
|
||||
/*- (float)outlineView:(NSOutlineView *)outlineView heightOfRowByItem:(id)item
|
||||
{
|
||||
return [item rowHeight];
|
||||
}*/
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Menu Management
|
||||
|
||||
// these next five methods are a crude hack - the items ought ot be in the responder chain themselves
|
||||
- (IBAction)createListEntry:(id)sender;
|
||||
{
|
||||
// This works by selecting an item that serves as a template (another LSTB), or knows how to create an item (LSTE) and passing the message on to it.
|
||||
id element = [dataList selectedItem];
|
||||
if([element respondsToSelector:@selector(createListEntry:)])
|
||||
{
|
||||
[element createListEntry:sender];
|
||||
[dataList reloadData];
|
||||
[dataList expandItem:[dataList selectedItem] expandChildren:YES];
|
||||
if(!liveEdit) [self setDocumentEdited:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)cut:(id)sender;
|
||||
{
|
||||
[[dataList selectedItem] cut:sender];
|
||||
[dataList reloadData];
|
||||
if(!liveEdit) [self setDocumentEdited:YES];
|
||||
}
|
||||
|
||||
- (IBAction)copy:(id)sender;
|
||||
{
|
||||
[[dataList selectedItem] copy:sender];
|
||||
[dataList reloadData];
|
||||
}
|
||||
|
||||
- (IBAction)paste:(id)sender;
|
||||
{
|
||||
[[dataList selectedItem] paste:sender];
|
||||
[dataList reloadData];
|
||||
if(!liveEdit) [self setDocumentEdited:YES];
|
||||
}
|
||||
|
||||
- (IBAction)clear:(id)sender;
|
||||
{
|
||||
[[dataList selectedItem] clear:sender];
|
||||
[dataList reloadData];
|
||||
if(!liveEdit) [self setDocumentEdited:YES];
|
||||
}
|
||||
|
||||
- (BOOL)validateMenuItem:(NSMenuItem*)item
|
||||
{
|
||||
Element *element = (Element*) [dataList selectedItem];
|
||||
if([item action] == @selector(createListEntry:)) return(element && [element respondsToSelector:@selector(createListEntry:)]);
|
||||
else if([item action] == @selector(cut:)) return(element && [element respondsToSelector:@selector(cut:)]);
|
||||
else if([item action] == @selector(copy:)) return(element && [element respondsToSelector:@selector(copy:)]);
|
||||
else if([item action] == @selector(paste:) && element && [element respondsToSelector:@selector(validateMenuItem:)])
|
||||
return([element validateMenuItem:item]);
|
||||
else if([item action] == @selector(clear:)) return(element && [element respondsToSelector:@selector(clear:)]);
|
||||
else if([item action] == @selector(saveDocument:)) return YES;
|
||||
else return NO;
|
||||
}
|
||||
|
||||
- (void)windowDidBecomeKey:(NSNotification *)notification
|
||||
{
|
||||
NSMenu *resourceMenu = [[[NSApp mainMenu] itemAtIndex:3] submenu];
|
||||
NSMenuItem *createItem = [resourceMenu itemAtIndex:[resourceMenu indexOfItemWithTarget:nil andAction:@selector(showCreateResourceSheet:)]];
|
||||
[createItem setTitle:NSLocalizedString(@"Create List Entry", nil)];
|
||||
[createItem setAction:@selector(createListEntry:)];
|
||||
}
|
||||
|
||||
- (void)windowDidResignKey:(NSNotification *)notification
|
||||
{
|
||||
NSMenu *resourceMenu = [[[NSApp mainMenu] itemAtIndex:3] submenu];
|
||||
NSMenuItem *createItem = [resourceMenu itemAtIndex:[resourceMenu indexOfItemWithTarget:nil andAction:@selector(createListEntry:)]];
|
||||
[createItem setTitle:NSLocalizedString(@"Create New Resource...", nil)];
|
||||
[createItem setAction:@selector(showCreateResourceSheet:)];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Toolbar Management
|
||||
|
||||
static NSString *RKTEToolbarIdentifier = @"com.nickshanks.resknife.templateeditor.toolbar";
|
||||
static NSString *RKTEDisplayTMPLIdentifier = @"com.nickshanks.resknife.templateeditor.toolbar.tmpl";
|
||||
|
||||
- (void)setupToolbar
|
||||
{
|
||||
/* 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:RKTEDisplayTMPLIdentifier] autorelease];
|
||||
[item setLabel:NSLocalizedString(@"Parsed TMPL", nil)];
|
||||
[item setPaletteLabel:NSLocalizedString(@"Display Parsed TMPL", nil)];
|
||||
[item setToolTip:NSLocalizedString(@"Display Parsed TMPL", nil)];
|
||||
[item setImage:[NSImage imageNamed:@"DisplayTMPL"]];
|
||||
[item setTarget:self];
|
||||
[item setAction:@selector(displayParsedTMPL:)];
|
||||
[toolbarItems setObject:item forKey:RKTEDisplayTMPLIdentifier];
|
||||
|
||||
NSToolbar *toolbar = [[[NSToolbar alloc] initWithIdentifier:RKTEToolbarIdentifier] autorelease];
|
||||
|
||||
// set toolbar properties
|
||||
[toolbar setVisible:NO];
|
||||
[toolbar setAutosavesConfiguration:YES];
|
||||
[toolbar setAllowsUserCustomization:YES];
|
||||
[toolbar setDisplayMode:NSToolbarDisplayModeLabelOnly];
|
||||
[toolbar setSizeMode:NSToolbarSizeModeSmall];
|
||||
|
||||
// attach toolbar to window
|
||||
[toolbar setDelegate:self];
|
||||
[[self window] setToolbar:toolbar];
|
||||
}
|
||||
|
||||
- (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag
|
||||
{
|
||||
return [toolbarItems objectForKey:itemIdentifier];
|
||||
}
|
||||
|
||||
- (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar
|
||||
{
|
||||
return [NSArray arrayWithObjects:RKTEDisplayTMPLIdentifier, NSToolbarFlexibleSpaceItemIdentifier, NSToolbarPrintItemIdentifier, nil];
|
||||
}
|
||||
|
||||
- (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar
|
||||
{
|
||||
return [NSArray arrayWithObjects:RKTEDisplayTMPLIdentifier, NSToolbarPrintItemIdentifier, NSToolbarCustomizeToolbarItemIdentifier, NSToolbarFlexibleSpaceItemIdentifier, NSToolbarSpaceItemIdentifier, NSToolbarSeparatorItemIdentifier, nil];
|
||||
}
|
||||
/*
|
||||
- (BOOL)validateToolbarItem:(NSToolbarItem *)item
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
*/
|
||||
- (void)displayParsedTMPL:(id)sender
|
||||
{
|
||||
[tmplDrawer toggle:sender];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Table Event Handling
|
||||
|
||||
@implementation NTOutlineView
|
||||
- (void)keyDown:(NSEvent *)event
|
||||
{
|
||||
Element *selectedItem = nil;
|
||||
int selectedRow = [self selectedRow];
|
||||
if(selectedRow != -1)
|
||||
selectedItem = [self selectedItem];
|
||||
|
||||
if(selectedItem && [selectedItem editable] && ([[event characters] isEqualToString:@"\r"] || [[event characters] isEqualToString:@"\t"]))
|
||||
[self editColumn:1 row:selectedRow withEvent:nil select:YES];
|
||||
else if(selectedItem && [selectedItem respondsToSelector:@selector(clear:)] && [[event characters] isEqualToString:[NSString stringWithCString:"\x7F"]])
|
||||
[[[self window] windowController] clear:nil];
|
||||
else [super keyDown:event];
|
||||
}
|
||||
- (BOOL)textView:(NSTextView *)textView doCommandBySelector:(SEL)selector
|
||||
{
|
||||
// pressed return, end editing
|
||||
if(selector == @selector(insertNewline:))
|
||||
{
|
||||
[[self window] makeFirstResponder:self];
|
||||
[self abortEditing];
|
||||
return YES;
|
||||
}
|
||||
return [super textView:textView doCommandBySelector:selector];
|
||||
}
|
||||
@end
|
BIN
NuTemplateEditor/Templates.rsrc
Normal file
BIN
NuTemplateEditor/Templates.rsrc
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
Loading…
Reference in New Issue
Block a user