diff --git a/NuTemplateEditor/NuTemplateLSTBElement.h b/NuTemplateEditor/NuTemplateLSTBElement.h index 49327c2..e214b9e 100644 --- a/NuTemplateEditor/NuTemplateLSTBElement.h +++ b/NuTemplateEditor/NuTemplateLSTBElement.h @@ -2,6 +2,8 @@ // NuTemplateLSTBElement.h // ResKnife (PB2) // +// Implements LSTB and LSTZ fields. +// // Created by Uli Kusterer on Tue Aug 05 2003. // Copyright (c) 2003 M. Uli Kusterer. All rights reserved. // diff --git a/NuTemplateEditor/NuTemplateLSTBElement.m b/NuTemplateEditor/NuTemplateLSTBElement.m index 6a4c370..f31790a 100644 --- a/NuTemplateEditor/NuTemplateLSTBElement.m +++ b/NuTemplateEditor/NuTemplateLSTBElement.m @@ -2,6 +2,8 @@ // NuTemplateLSTBElement.m // ResKnife (PB2) // +// Implements LSTB and LSTZ fields. +// // Created by Uli Kusterer on Tue Aug 05 2003. // Copyright (c) 2003 M. Uli Kusterer. All rights reserved. // @@ -28,6 +30,8 @@ if( [[obj type] isEqualToString: @"LSTE"] ) { endElement = [obj retain]; + if( [type isEqualToString: @"LSTZ"] ) + [endElement setWritesZeroByte:YES]; break; } [subElements addObject: obj]; @@ -35,19 +39,38 @@ } --(void) readDataFrom: (NuTemplateStream*)stream +-(void) readDataForElements: (NuTemplateStream*)stream { NSEnumerator *enny = [subElements objectEnumerator]; - NuTemplateElement *el, *nextItem; - unsigned int bytesToGoAtStart = [stream bytesToGo]; + NuTemplateElement *el; - /* Fill this first list element with data: - If there is no more data in the stream, the items will - fill themselves with default values. */ while( el = [enny nextObject] ) { [el readDataFrom: stream]; } +} + + +-(void) readDataFrom: (NuTemplateStream*)stream +{ + BOOL isZeroTerminated = [type isEqualToString: @"LSTZ"]; + NSEnumerator *enny = [subElements objectEnumerator]; + NuTemplateElement *el, *nextItem; + unsigned int bytesToGoAtStart = [stream bytesToGo]; + char termByte = 0; + + /* Fill this first list element with data: + If there is no more data in the stream, the items will + fill themselves with default values. */ + if( isZeroTerminated ) + { + termByte = 0; + [stream peekAmount:1 toBuffer:&termByte]; // "Peek" doesn't change the read offset. + if( termByte != 0 ) + [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. */ @@ -55,6 +78,15 @@ { while( [stream bytesToGo] > 0 ) { + if( isZeroTerminated ) // Is zero-terminated list? Check whether there is a termination byte. + { + termByte = 0; + [stream peekAmount:1 toBuffer:&termByte]; // "Peek" doesn't change the read offset. + if( termByte == 0 ) + break; // No need to actually read the peeked byte, LSTE will do that. + } + + // Actually read the item: nextItem = [[self copy] autorelease]; // Make another list item just like this one. [nextItem setContaining: nil]; // Make sure it doesn't get into this "if" clause. [containing addObject: nextItem]; // Add it below ourselves. @@ -68,6 +100,7 @@ [containing addObject: tlee]; [tlee setContaining: containing]; [tlee setGroupElemTemplate: self]; + [tlee readDataFrom: stream]; // If LSTE has data to read (e.g. if we're an LSTZ, the terminating byte), let it do that! if( bytesToGoAtStart == 0 ) // It's an empty list. Delete this LSTB again, so we only have the empty LSTE. { diff --git a/NuTemplateEditor/NuTemplateLSTEElement.h b/NuTemplateEditor/NuTemplateLSTEElement.h index ecd2f6a..ac0e300 100644 --- a/NuTemplateEditor/NuTemplateLSTEElement.h +++ b/NuTemplateEditor/NuTemplateLSTEElement.h @@ -13,10 +13,14 @@ @interface NuTemplateLSTEElement : NuTemplateGroupElement { NuTemplateGroupElement* groupElemTemplate; // The item of which we're to create a copy. + BOOL writesZeroByte; // Write a terminating zero-byte when writing out this item (used by LSTZ). } -(IBAction) showCreateResourceSheet: (id)sender; +-(void) setWritesZeroByte: (BOOL)n; +-(BOOL) writesZeroByte; + -(void) setGroupElemTemplate: (NuTemplateGroupElement*)e; -(NuTemplateGroupElement*) groupElemTemplate; diff --git a/NuTemplateEditor/NuTemplateLSTEElement.m b/NuTemplateEditor/NuTemplateLSTEElement.m index e69d538..25c0c50 100644 --- a/NuTemplateEditor/NuTemplateLSTEElement.m +++ b/NuTemplateEditor/NuTemplateLSTEElement.m @@ -40,12 +40,10 @@ -(void) readDataFrom: (NuTemplateStream*)stream { - NSEnumerator* enny = [subElements objectEnumerator]; - NuTemplateElement* el; - - while( el = [enny nextObject] ) + if( writesZeroByte ) { - [el readDataFrom: stream]; + char termByte; + [stream readAmount:1 toBuffer: &termByte]; } } @@ -53,12 +51,16 @@ // Doesn't write any sub-elements because this is simply a placeholder to allow for empty lists: -(unsigned int) sizeOnDisk { - return 0; + return writesZeroByte ? 1 : 0; } -(void) writeDataTo: (NuTemplateStream*)stream { - + if( writesZeroByte ) + { + char fillByte = 0; + [stream writeAmount:sizeof(fillByte) fromBuffer: &fillByte]; + } } @@ -74,11 +76,23 @@ } +-(void) setWritesZeroByte: (BOOL)n +{ + writesZeroByte = n; +} + +-(BOOL) writesZeroByte +{ + return writesZeroByte; +} + + -(id) copyWithZone: (NSZone*)zone { NuTemplateLSTEElement* el = [super copyWithZone: zone]; [el setGroupElemTemplate: [self groupElemTemplate]]; + [el setWritesZeroByte: [self writesZeroByte]]; return el; } diff --git a/NuTemplateEditor/NuTemplateStream.h b/NuTemplateEditor/NuTemplateStream.h index 0830516..70e808a 100644 --- a/NuTemplateEditor/NuTemplateStream.h +++ b/NuTemplateEditor/NuTemplateStream.h @@ -31,6 +31,7 @@ -(NuTemplateElement*) readOneElement; // For parsing of 'TMPL' resource as template. -(void) readAmount: (unsigned int)l toBuffer: (void*)buf; // For reading data from the resource. +-(void) peekAmount: (unsigned int)l toBuffer: (void*)buf; // For examining data w/o advancing the read/write mark. -(void) writeAmount: (unsigned int)l fromBuffer: (void*)buf; // For writing data back to the resource. diff --git a/NuTemplateEditor/NuTemplateStream.m b/NuTemplateEditor/NuTemplateStream.m index 1f05b83..2b8bdff 100644 --- a/NuTemplateEditor/NuTemplateStream.m +++ b/NuTemplateEditor/NuTemplateStream.m @@ -108,6 +108,16 @@ } +-(void) peekAmount: (unsigned int)l toBuffer: (void*)buf +{ + if( l > bytesToGo ) + l = bytesToGo; + + if( l > 0 ) + memmove( buf, data, l ); +} + + -(void) writeAmount: (unsigned int)l fromBuffer: (void*)buf { if( l > bytesToGo ) diff --git a/NuTemplateEditor/NuTemplateWindowController.h b/NuTemplateEditor/NuTemplateWindowController.h index 2f9e257..b10d04c 100644 --- a/NuTemplateEditor/NuTemplateWindowController.h +++ b/NuTemplateEditor/NuTemplateWindowController.h @@ -53,6 +53,7 @@ -(IBAction) copy: (id)sender; -(IBAction) paste: (id)sender; -(IBAction) clear: (id)sender; +-(IBAction) saveDocument: (id)sender; @end diff --git a/NuTemplateEditor/NuTemplateWindowController.m b/NuTemplateEditor/NuTemplateWindowController.m index 8df4b74..798d09e 100644 --- a/NuTemplateEditor/NuTemplateWindowController.m +++ b/NuTemplateEditor/NuTemplateWindowController.m @@ -193,6 +193,7 @@ if( [fieldReg count] == 0 ) { [fieldReg setObject: [NuTemplateLSTBElement class] forKey: @"LSTB"]; + [fieldReg setObject: [NuTemplateLSTBElement class] forKey: @"LSTZ"]; [fieldReg setObject: [NuTemplateLSTEElement class] forKey: @"LSTE"]; [fieldReg setObject: [NuTemplateTNAMElement class] forKey: @"TNAM"]; [fieldReg setObject: [NuTemplatePSTRElement class] forKey: @"PSTR"]; @@ -328,6 +329,8 @@ return( [selElement validateMenuItem: item] ); else if( [item action] == @selector(clear:) ) return( selElement != nil && [selElement respondsToSelector: @selector(clear:)] ); + else if( [item action] == @selector(saveDocument:) ) + return YES; else return NO; } @@ -342,6 +345,12 @@ } +-(IBAction) saveDocument: (id)sender +{ + [self writeResData]; +} + + -(BOOL) windowShouldClose: (id)sender // Window delegate. { [self writeResData]; // Save resource. diff --git a/TODO.txt b/TODO.txt index 8da3276..e7aecd0 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,3 +1,5 @@ -> "Open as Hex" displays "(null)" as the document name. Why? -> Changing the type/creator of a file isn't written to disk by ResourceDocument. --> Create small versions of the doc icons in Photoshop instead of letting IconComposer use its cheap scaling on them. \ No newline at end of file +-> Create small versions of the doc icons in Photoshop instead of letting IconComposer use its cheap scaling on them. +-> Auto-uncollapse list items in template editor when they are created and when a resource is opened. +-> Template editor should maintain "dirty" flag for resource. \ No newline at end of file