mirror of
https://github.com/nickshanks/ResKnife.git
synced 2024-11-16 06:05:05 +00:00
Extend LSTB/LSTE to also handle LSTZ-style zero-terminated lists.
This commit is contained in:
parent
eb2527cf0f
commit
04e81cb47d
@ -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.
|
||||||
//
|
//
|
||||||
|
@ -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.
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
|
|
||||||
|
@ -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 )
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
2
TODO.txt
2
TODO.txt
@ -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.
|
Loading…
Reference in New Issue
Block a user