Extend LSTB/LSTE to also handle LSTZ-style zero-terminated lists.

This commit is contained in:
Uli Kusterer 2003-08-17 00:48:19 +02:00
parent eb2527cf0f
commit 04e81cb47d
9 changed files with 90 additions and 14 deletions

View File

@ -2,6 +2,8 @@
// NuTemplateLSTBElement.h // NuTemplateLSTBElement.h
// ResKnife (PB2) // ResKnife (PB2)
// //
// Implements LSTB and LSTZ fields.
//
// Created by Uli Kusterer on Tue Aug 05 2003. // Created by Uli Kusterer on Tue Aug 05 2003.
// Copyright (c) 2003 M. Uli Kusterer. All rights reserved. // Copyright (c) 2003 M. Uli Kusterer. All rights reserved.
// //

View File

@ -2,6 +2,8 @@
// NuTemplateLSTBElement.m // NuTemplateLSTBElement.m
// ResKnife (PB2) // ResKnife (PB2)
// //
// Implements LSTB and LSTZ fields.
//
// Created by Uli Kusterer on Tue Aug 05 2003. // Created by Uli Kusterer on Tue Aug 05 2003.
// Copyright (c) 2003 M. Uli Kusterer. All rights reserved. // Copyright (c) 2003 M. Uli Kusterer. All rights reserved.
// //
@ -28,6 +30,8 @@
if( [[obj type] isEqualToString: @"LSTE"] ) if( [[obj type] isEqualToString: @"LSTE"] )
{ {
endElement = [obj retain]; endElement = [obj retain];
if( [type isEqualToString: @"LSTZ"] )
[endElement setWritesZeroByte:YES];
break; break;
} }
[subElements addObject: obj]; [subElements addObject: obj];
@ -35,19 +39,38 @@
} }
-(void) readDataFrom: (NuTemplateStream*)stream -(void) readDataForElements: (NuTemplateStream*)stream
{ {
NSEnumerator *enny = [subElements objectEnumerator]; NSEnumerator *enny = [subElements objectEnumerator];
NuTemplateElement *el, *nextItem; NuTemplateElement *el;
unsigned int bytesToGoAtStart = [stream bytesToGo];
/* 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] ) while( el = [enny nextObject] )
{ {
[el readDataFrom: stream]; [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, /* Read additional elements until we have enough items,
except if we're not the first item in our list. */ except if we're not the first item in our list. */
@ -55,6 +78,15 @@
{ {
while( [stream bytesToGo] > 0 ) 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 = [[self copy] autorelease]; // Make another list item just like this one.
[nextItem setContaining: nil]; // Make sure it doesn't get into this "if" clause. [nextItem setContaining: nil]; // Make sure it doesn't get into this "if" clause.
[containing addObject: nextItem]; // Add it below ourselves. [containing addObject: nextItem]; // Add it below ourselves.
@ -68,6 +100,7 @@
[containing addObject: tlee]; [containing addObject: tlee];
[tlee setContaining: containing]; [tlee setContaining: containing];
[tlee setGroupElemTemplate: self]; [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. if( bytesToGoAtStart == 0 ) // It's an empty list. Delete this LSTB again, so we only have the empty LSTE.
{ {

View File

@ -13,10 +13,14 @@
@interface NuTemplateLSTEElement : NuTemplateGroupElement @interface NuTemplateLSTEElement : NuTemplateGroupElement
{ {
NuTemplateGroupElement* groupElemTemplate; // The item of which we're to create a copy. 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; -(IBAction) showCreateResourceSheet: (id)sender;
-(void) setWritesZeroByte: (BOOL)n;
-(BOOL) writesZeroByte;
-(void) setGroupElemTemplate: (NuTemplateGroupElement*)e; -(void) setGroupElemTemplate: (NuTemplateGroupElement*)e;
-(NuTemplateGroupElement*) groupElemTemplate; -(NuTemplateGroupElement*) groupElemTemplate;

View File

@ -40,12 +40,10 @@
-(void) readDataFrom: (NuTemplateStream*)stream -(void) readDataFrom: (NuTemplateStream*)stream
{ {
NSEnumerator* enny = [subElements objectEnumerator]; if( writesZeroByte )
NuTemplateElement* el;
while( el = [enny nextObject] )
{ {
[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: // Doesn't write any sub-elements because this is simply a placeholder to allow for empty lists:
-(unsigned int) sizeOnDisk -(unsigned int) sizeOnDisk
{ {
return 0; return writesZeroByte ? 1 : 0;
} }
-(void) writeDataTo: (NuTemplateStream*)stream -(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 -(id) copyWithZone: (NSZone*)zone
{ {
NuTemplateLSTEElement* el = [super copyWithZone: zone]; NuTemplateLSTEElement* el = [super copyWithZone: zone];
[el setGroupElemTemplate: [self groupElemTemplate]]; [el setGroupElemTemplate: [self groupElemTemplate]];
[el setWritesZeroByte: [self writesZeroByte]];
return el; return el;
} }

View File

@ -31,6 +31,7 @@
-(NuTemplateElement*) readOneElement; // For parsing of 'TMPL' resource as template. -(NuTemplateElement*) readOneElement; // For parsing of 'TMPL' resource as template.
-(void) readAmount: (unsigned int)l toBuffer: (void*)buf; // For reading data from the resource. -(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. -(void) writeAmount: (unsigned int)l fromBuffer: (void*)buf; // For writing data back to the resource.

View File

@ -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 -(void) writeAmount: (unsigned int)l fromBuffer: (void*)buf
{ {
if( l > bytesToGo ) if( l > bytesToGo )

View File

@ -53,6 +53,7 @@
-(IBAction) copy: (id)sender; -(IBAction) copy: (id)sender;
-(IBAction) paste: (id)sender; -(IBAction) paste: (id)sender;
-(IBAction) clear: (id)sender; -(IBAction) clear: (id)sender;
-(IBAction) saveDocument: (id)sender;
@end @end

View File

@ -193,6 +193,7 @@
if( [fieldReg count] == 0 ) if( [fieldReg count] == 0 )
{ {
[fieldReg setObject: [NuTemplateLSTBElement class] forKey: @"LSTB"]; [fieldReg setObject: [NuTemplateLSTBElement class] forKey: @"LSTB"];
[fieldReg setObject: [NuTemplateLSTBElement class] forKey: @"LSTZ"];
[fieldReg setObject: [NuTemplateLSTEElement class] forKey: @"LSTE"]; [fieldReg setObject: [NuTemplateLSTEElement class] forKey: @"LSTE"];
[fieldReg setObject: [NuTemplateTNAMElement class] forKey: @"TNAM"]; [fieldReg setObject: [NuTemplateTNAMElement class] forKey: @"TNAM"];
[fieldReg setObject: [NuTemplatePSTRElement class] forKey: @"PSTR"]; [fieldReg setObject: [NuTemplatePSTRElement class] forKey: @"PSTR"];
@ -328,6 +329,8 @@
return( [selElement validateMenuItem: item] ); return( [selElement validateMenuItem: item] );
else if( [item action] == @selector(clear:) ) else if( [item action] == @selector(clear:) )
return( selElement != nil && [selElement respondsToSelector: @selector(clear:)] ); return( selElement != nil && [selElement respondsToSelector: @selector(clear:)] );
else if( [item action] == @selector(saveDocument:) )
return YES;
else return NO; else return NO;
} }
@ -342,6 +345,12 @@
} }
-(IBAction) saveDocument: (id)sender
{
[self writeResData];
}
-(BOOL) windowShouldClose: (id)sender // Window delegate. -(BOOL) windowShouldClose: (id)sender // Window delegate.
{ {
[self writeResData]; // Save resource. [self writeResData]; // Save resource.

View File

@ -1,3 +1,5 @@
-> "Open as Hex" displays "(null)" as the document name. Why? -> "Open as Hex" displays "(null)" as the document name. Why?
-> Changing the type/creator of a file isn't written to disk by ResourceDocument. -> 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. -> 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.