ResKnife/Cocoa/Plug-Ins/Template Editor/ElementLSTB.mm

250 lines
6.6 KiB
Plaintext

#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 = (ElementOCNT *) 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