#import "ElementPSTR.h" // implements PSTR, OSTR, ESTR, BSTR, WSTR, LSTR, CSTR, OCST, ECST, CHAR, TNAM @implementation ElementPSTR - (id)initForType:(NSString *)t withLabel:(NSString *)l { self = [super initForType:t withLabel:l]; if(!self) return nil; value = [@"" retain]; if ([t isEqualToString:@"PSTR"] || [t isEqualToString:@"BSTR"]) { _lengthBytes = 1; _maxLength = UINT8_MAX; _minLength = 0; _terminatingByte = NO; _pad = kNoPadding; _alignment = 0; } else if([t isEqualToString:@"WSTR"]) { _lengthBytes = 2; _maxLength = UINT16_MAX; _minLength = 0; _terminatingByte = NO; _pad = kNoPadding; _alignment = 0; } else if([t isEqualToString:@"LSTR"]) { _lengthBytes = 4; _maxLength = UINT32_MAX; _minLength = 0; _terminatingByte = NO; _pad = kNoPadding; _alignment = 0; } else if([t isEqualToString:@"OSTR"]) { _lengthBytes = 1; _maxLength = UINT8_MAX-1; _minLength = 0; _terminatingByte = NO; _pad = kPadToOddLength; _alignment = 0; } else if([t isEqualToString:@"ESTR"]) { _lengthBytes = 1; _maxLength = UINT8_MAX; _minLength = 0; _terminatingByte = NO; _pad = kPadToEvenLength; _alignment = 0; } else if([t isEqualToString:@"CSTR"]) { _lengthBytes = 0; _maxLength = 0; _minLength = 0; _terminatingByte = YES; _pad = kNoPadding; _alignment = 0; } else if([t isEqualToString:@"OCST"]) { _lengthBytes = 0; _maxLength = 0; _minLength = 0; _terminatingByte = YES; _pad = kPadToOddLength; _alignment = 0; } else if([t isEqualToString:@"ECST"]) { _lengthBytes = 0; _maxLength = 0; _minLength = 0; _terminatingByte = YES; _pad = kPadToEvenLength; _alignment = 0; } else if([t isEqualToString:@"CHAR"]) { _lengthBytes = 0; _maxLength = 1; _minLength = 1; _terminatingByte = NO; _pad = kNoPadding; _alignment = 0; } else if([t isEqualToString:@"TNAM"]) { _lengthBytes = 0; _maxLength = 4; _minLength = 4; _terminatingByte = NO; _pad = kNoPadding; _alignment = 0; } // temp until keyed values are implemented else if([t isEqualToString:@"KCHR"]) { _lengthBytes = 0; _maxLength = 1; _minLength = 1; _terminatingByte = NO; _pad = kNoPadding; _alignment = 0; } else if([t isEqualToString:@"KTYP"]) { _lengthBytes = 0; _maxLength = 4; _minLength = 4; _terminatingByte = NO; _pad = kNoPadding; _alignment = 0; } return self; } - (void)dealloc { [value release]; [super dealloc]; } - (id)copyWithZone:(NSZone*)zone { ElementPSTR *element = [super copyWithZone:zone]; [element setStringValue:value]; [element setMaxLength:_maxLength]; [element setMinLength:_minLength]; [element setPad:_pad]; [element setTerminatingByte:_terminatingByte]; [element setLengthBytes:_lengthBytes]; [element setAlignment:_alignment]; return element; } - (void)readDataFrom:(TemplateStream *)stream { // get string length UInt32 length = 0; if(_lengthBytes > 0) { [stream readAmount:_lengthBytes toBuffer:&length]; #if __BIG_ENDIAN__ length >>= (4 - _lengthBytes) << 3; #else #warning FIXME: This probably doesn't work for WSTR and LSTR on intel machines #endif } if(_terminatingByte) length += [stream bytesToNull]; if(_maxLength && length > _maxLength) length = _maxLength; if(length < _minLength) length = _minLength; // read string void *buffer = malloc(length); if(_minLength) memset(buffer, 0, _minLength); [stream readAmount:length toBuffer:buffer]; if([NSString instancesRespondToSelector:@selector(initWithBytesNoCopy:length:encoding:freeWhenDone:)]) // 10.3 [self setStringValue:[[[NSString alloc] initWithBytesNoCopy:buffer length:length encoding:NSMacOSRomanStringEncoding freeWhenDone:YES] autorelease]]; else { [self setStringValue:[[[NSString alloc] initWithBytes:buffer length:length encoding:NSMacOSRomanStringEncoding] autorelease]]; free(buffer); } // skip over empty bytes if(_terminatingByte) [stream advanceAmount:1 pad:NO]; if(_pad == kPadToOddLength && (length + _terminatingByte ? 1:0) % 2 == 0) [stream advanceAmount:1 pad:NO]; if(_pad == kPadToEvenLength && (length + _terminatingByte ? 1:0) % 2 == 1) [stream advanceAmount:1 pad:NO]; // alignment unhandled here } - (unsigned int)sizeOnDisk { UInt32 length; if([value respondsToSelector:@selector(lengthOfBytesUsingEncoding:)]) // 10.4 length = [value lengthOfBytesUsingEncoding:NSMacOSRomanStringEncoding]; else length = [value cStringLength]; if(_maxLength && length > _maxLength) length = _maxLength; if(length < _minLength) length = _minLength; length += _lengthBytes + (_terminatingByte? 1:0); if(_pad == kPadToOddLength && length % 2 == 0) length++; if(_pad == kPadToEvenLength && length % 2 == 1) length++; // don't know how to deal with alignment here return length; } - (void)writeDataTo:(TemplateStream *)stream { // write string UInt32 length = [value length], writeLength; if(_maxLength && length > _maxLength) length = _maxLength; #if __BIG_ENDIAN__ writeLength = length << ((4 - _lengthBytes) << 3); #else #warning FIXME: This probably doesn't work for WSTR and LSTR on intel machines #endif if(_lengthBytes) [stream writeAmount:_lengthBytes fromBuffer:&writeLength]; if ([value canBeConvertedToEncoding:NSMacOSRomanStringEncoding]) { const void *buffer = NULL; if([value respondsToSelector:@selector(cStringUsingEncoding:)]) // 10.4 buffer = [value cStringUsingEncoding:NSMacOSRomanStringEncoding]; else { NSData *data = [value dataUsingEncoding:NSMacOSRomanStringEncoding]; buffer = [data bytes]; } if(buffer) [stream writeAmount:length fromBuffer:buffer]; else [stream advanceAmount:length pad:YES]; } else { #warning FIXME: This code should display a warning saying that the string in the PSTR is not MacOSRoman } // pad to minimum length with spaces if(length < _minLength) { SInt32 padAmount = _minLength - length; while(padAmount > 0) { UInt32 spaces = ' '; [stream writeAmount:(padAmount < 4)? padAmount:4 fromBuffer:&spaces]; length += (padAmount < 4)? padAmount:4; padAmount -= 4; } } if(_terminatingByte) [stream advanceAmount:1 pad:YES]; if(_pad == kPadToOddLength && (length + _lengthBytes + (_terminatingByte? 1:0)) % 2 == 0) [stream advanceAmount:1 pad:YES]; if(_pad == kPadToEvenLength && (length + _lengthBytes + (_terminatingByte? 1:0)) % 2 == 1) [stream advanceAmount:1 pad:YES]; } - (NSString *)stringValue { return value; } - (void)setStringValue:(NSString *)str { id old = value; value = [str copy]; [old release]; } - (void)setMaxLength:(UInt32)v { _maxLength = v; } - (void)setMinLength:(UInt32)v { _minLength = v; } - (void)setPad:(enum StringPadding)v { _pad = v; } - (void)setTerminatingByte:(BOOL)v { _terminatingByte = v; } - (void)setLengthBytes:(int)v { _lengthBytes = v; } - (void)setAlignment:(int)v { _alignment = v; } @end