ResKnife/NuTemplateEditor/TemplateStream.m
Nicholas Shanks fee2452785 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
2014-02-20 00:53:03 +00:00

314 lines
10 KiB
Objective-C

#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