Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
529 lines (463 sloc) 12 KB
/*
* The Cheat - The legendary universal game trainer for Mac OS X.
* http://www.brokenzipper.com/trac/wiki/TheCheat
*
* Copyright (c) 2003-2011, Charles McGarvey et al.
*
* Distributable under the terms and conditions of the 2-clause BSD
* license; see the file COPYING for the legal text of the license.
*/
#import "Variable.h"
@interface Variable ( PrivateAPI )
- (void)_setType:(TCVariableType)type;
- (void)_setIntegerSign:(TCIntegerSign)sign;
@end
@implementation Variable
- (id)init
{
return [self initWithType:TCInt32 integerSign:TCSigned];
}
- (id)initWithType:(TCVariableType)type
{
return [self initWithType:type integerSign:TCSigned];
}
- (id)initWithType:(TCVariableType)type integerSign:(TCIntegerSign)sign // DESIGNATED
{
if ( self = [super init] ) {
_isValueValid = YES;
_enabled = YES;
[self _setType:type];
[self _setIntegerSign:sign];
}
return self;
}
- (void)setProcess:(Process *)newProcess
{
if (process != newProcess && [newProcess pid] > 0)
{
_isEmulated = [newProcess isEmulated];
[newProcess retain];
[process release];
process = newProcess;
}
}
- (Process *)process
{
return process;
}
- (BOOL)isEmulated
{
return _isEmulated;
}
- (void)dealloc
{
if ( _value ) {
free( _value );
}
[super dealloc];
}
// #############################################################################
#pragma mark NSCoding
// #############################################################################
- (id)initWithCoder:(NSCoder *)coder
{
if ( self = [super init] ) {
[coder decodeValueOfObjCType:@encode(TCVariableType) at:&_type];
[coder decodeValueOfObjCType:@encode(TCIntegerSign) at:&_integerSign];
[coder decodeValueOfObjCType:@encode(TCAddress) at:&_address];
void *value = [coder decodeBytesWithReturnedLength:&_size];
if (_type == TCString || _type == TCInt8)
{
[self setValue:value];
}
else if (_type == TCCiv5Int) {
int32_t newVariable = CFSwapInt32BigToHost(*((int32_t *)value));
[self setValue:&newVariable];
}
else if (_type == TCInt16)
{
int16_t newVariable = CFSwapInt16BigToHost(*((int16_t *)value));
[self setValue:&newVariable];
}
else if (_type == TCInt32)
{
int32_t newVariable = CFSwapInt32BigToHost(*((int32_t *)value));
[self setValue:&newVariable];
}
else if (_type == TCInt64)
{
int64_t newVariable = CFSwapInt64BigToHost(*((int64_t *)value));
[self setValue:&newVariable];
}
else if (_type == TCFloat)
{
#ifdef __LITTLE_ENDIAN__
CFSwappedFloat32 newVariable = CFConvertFloat32HostToSwapped(*((float *)value));
[self setValue:&(newVariable.v)];
#else
[self setValue:value];
#endif
}
else if (_type == TCDouble)
{
#ifdef __LITTLE_ENDIAN__
CFSwappedFloat64 newVariable = CFConvertDoubleHostToSwapped(*((double *)value));
[self setValue:&(newVariable.v)];
#else
[self setValue:value];
#endif
}
[coder decodeValueOfObjCType:@encode(BOOL) at:&_isValueValid];
[coder decodeValueOfObjCType:@encode(BOOL) at:&_enabled];
[coder decodeValueOfObjCType:@encode(int) at:&_tag];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder
{
[coder encodeValueOfObjCType:@encode(TCVariableType) at:&_type];
[coder encodeValueOfObjCType:@encode(TCIntegerSign) at:&_integerSign];
[coder encodeValueOfObjCType:@encode(TCAddress) at:&_address];
if (_type == TCString || _type == TCInt8)
{
[coder encodeBytes:_value length:_size];
}
else if (_type == TCInt16)
{
int16_t newVariable = CFSwapInt16HostToBig(*((int16_t *)_value));
[coder encodeBytes:&newVariable length:_size];
}
else if (_type == TCCiv5Int) {
int32_t newVariable = CFSwapInt32HostToBig(*((int32_t *)_value));
[coder encodeBytes:&newVariable length:_size];
}
else if (_type == TCInt32)
{
int32_t newVariable = CFSwapInt32HostToBig(*((int32_t *)_value));
[coder encodeBytes:&newVariable length:_size];
}
else if (_type == TCInt64)
{
int64_t newVariable = CFSwapInt64HostToBig(*((int64_t *)_value));
[coder encodeBytes:&newVariable length:_size];
}
else if (_type == TCFloat)
{
#ifdef __LITTLE_ENDIAN__
CFSwappedFloat32 newVariable = CFConvertFloat32HostToSwapped(*((float *)_value));
[coder encodeBytes:&newVariable length:_size];
#else
[coder encodeBytes:&_value length:_size];
#endif
}
else if (_type == TCDouble)
{
#ifdef __LITTLE_ENDIAN__
CFSwappedFloat64 newVariable = CFConvertDoubleHostToSwapped(*((double *)_value));
[coder encodeBytes:&newVariable length:_size];
#else
[coder encodeBytes:_value length:_size];
#endif
}
[coder encodeValueOfObjCType:@encode(BOOL) at:&_isValueValid];
[coder encodeValueOfObjCType:@encode(BOOL) at:&_enabled];
[coder encodeValueOfObjCType:@encode(int) at:&_tag];
}
// #############################################################################
#pragma mark Accessors
// #############################################################################
- (TCVariableType)type
{
return _type;
}
- (void)_setType:(TCVariableType)type
{
_type = type;
// set the size of the value
switch ( _type ) {
case TCInt64:
case TCDouble: _size = 8;
break;
case TCInt32:
case TCFloat: _size = 4;
break;
case TCInt16: _size = 2;
break;
case TCCiv5Int: _size = 4;
break;
case TCInt8: _size = 1;
break;
}
if ( !_value ) {
_value = calloc( 1, _size );
}
}
- (TCIntegerSign)integerSign
{
return _integerSign;
}
- (void)_setIntegerSign:(TCIntegerSign)sign
{
_integerSign = sign;
}
- (NSString *)typeString
{
switch ( _type ) {
case TCDouble: return @"Double";
case TCFloat: return @"Float";
case TCString: return @"ASCII String";
}
if ( _integerSign == TCUnsigned ) {
switch ( _type ) {
case TCInt64: return @"64-bit Unsigned Integer";
case TCInt32: return @"32-bit Unsigned Integer";
case TCInt16: return @"16-bit Unsigned Integer";
case TCInt8: return @"08-bit Unsigned Integer";
case TCCiv5Int: return @"Civ5 Unsigned Integer";
}
}
else {
switch ( _type ) {
case TCInt64: return @"64-bit Integer";
case TCInt32: return @"32-bit Integer";
case TCInt16: return @"16-bit Integer";
case TCInt8: return @"08-bit Integer";
case TCCiv5Int: return @"Civ5 Integer";
}
}
return @"";
}
- (TCAddress)address
{
return _address;
}
- (void)setAddress:(TCAddress)addr
{
_address = addr;
}
- (NSString *)addressString
{
// return [NSString stringWithFormat:@"%0.8X", _address];
return [NSString stringWithFormat:(_address & 0xffffffff00000000ULL) ? @"%0.16qX": @"%0.8X", _address];
}
- (BOOL)setAddressString:(NSString *)string
{
NSScanner *scanner = [NSScanner scannerWithString:string];
TCAddress address;
#if MAC_OS_X_VERSION_10_5 <= MAC_OS_X_VERSION_MAX_ALLOWED
if ( [scanner scanHexLongLong:(unsigned long long *)(&address)] ) {
#else
if ( [scanner scanHexInt:(unsigned *)(&address)] ) {
#endif
[self setAddress:address];
return YES;
}
return NO;
}
- (void const *)value
{
return _value;
}
- (void)setValue:(void const *)value
{
if ( !_value ) {
_value = malloc( _size );
}
_isValueValid = YES;
memcpy( _value, value, _size );
}
- (void)setValue:(void const *)value size:(unsigned)size
{
// make sure the size doesn't exceed the maximum
size = MIN( size, TC_MAX_VAR_SIZE );
// only string variables can have the value size changed
if ( (_type == TCString) && (_size != size) && _value ) {
void *newValue = realloc( _value, size );
if ( newValue ) {
_value = newValue;
_size = size;
}
}
_size = MIN( _size, size );
[self setValue:value];
}
- (NSString *)stringValue
{
switch ( _type ) {
case TCDouble: return [NSString stringWithFormat:@"%.1lf", *(double *)[self value]];
case TCFloat: return [NSString stringWithFormat:@"%.1f", *(float *)[self value]];
case TCString: return [NSString stringWithCString:[self value] length:[self valueSize]];
}
if ( _integerSign == TCUnsigned ) {
switch ( _type ) {
case TCInt64: return [NSString stringWithFormat:@"%llu", *(UInt64 *)[self value]];
case TCInt32: return [NSString stringWithFormat:@"%u", *(UInt32 *)[self value]];
case TCInt16: return [NSString stringWithFormat:@"%u", *(UInt16 *)[self value]];
case TCCiv5Int: return [NSString stringWithFormat:@"%u (%u)",*(UInt16 *)[self value]/100,*(UInt16 *)[self value]%100];
case TCInt8: return [NSString stringWithFormat:@"%u", *(UInt8 *)[self value]];
}
}
else {
switch ( _type ) {
case TCInt64: return [NSString stringWithFormat:@"%lli", *(SInt64 *)[self value]];
case TCInt32: return [NSString stringWithFormat:@"%i", *(SInt32 *)[self value]];
case TCInt16: return [NSString stringWithFormat:@"%i", *(SInt16 *)[self value]];
case TCCiv5Int: return [NSString stringWithFormat:@"%i (%u)",*(UInt16 *)[self value]/100,*(UInt16 *)[self value]%100];
case TCInt8: return [NSString stringWithFormat:@"%i", *(SInt8 *)[self value]];
}
}
return @"foobar";
}
- (BOOL)setStringValue:(NSString *)string
{
NSScanner *scanner = [NSScanner scannerWithString:string];
// invalid until proven valid
_isValueValid = NO;
switch ( _type ) {
case TCInt64:
{
SInt64 value;
if ( [scanner scanLongLong:(long long *)(&value)] ) {
[self setValue:&value];
}
break;
}
case TCInt32:
{
SInt32 value;
// if ( [scanner scanInt:(int *)(&value)] ) {
int integer;
if ( [scanner scanInt:&integer] ) {
value = integer;
[self setValue:&value];
}
break;
}
case TCInt16:
{
int integer;
SInt16 value;
if ( [scanner scanInt:&integer] ) {
value = integer;
[self setValue:&value];
}
break;
}
case TCCiv5Int:
{
SInt32 value;
// if ( [scanner scanInt:(int *)(&value)] ) {
int integer;
if ( [scanner scanInt:&integer] ) {
value = integer * 100;
[self setValue:&value];
}
break;
}
case TCInt8:
{
int integer;
SInt8 value;
if ( [scanner scanInt:&integer] ) {
value = integer;
[self setValue:&value];
}
break;
}
case TCString:
{
char *str = (char *)[string lossyCString];
unsigned len = strlen( str );
[self setValue:str size:len];
break;
}
case TCFloat:
{
float value;
if ( [scanner scanFloat:&value] ) {
[self setValue:&value];
}
break;
}
case TCDouble:
{
double value;
if ( [scanner scanDouble:&value] ) {
[self setValue:&value];
}
break;
}
}
return [self isValueValid];
}
// this only converts the byte order of the value at buffer if the process is running under rosetta on an intel mac
// floats and double's byte ordering should not be changed when searching for values because they may be swapped to '0.0'
void bigEndianValue(void *buffer, Variable *variable)
{
if (variable->_isEmulated)
{
if (variable->_type == TCInt16)
{
int16_t newValue = CFSwapInt16HostToBig(*((int16_t *)buffer));
memcpy(buffer, &newValue, sizeof(int16_t));
}
if (variable->_type == TCCiv5Int)
{
int32_t newValue = CFSwapInt32HostToBig(*((int32_t *)buffer));
memcpy(buffer, &newValue, sizeof(int32_t));
}
else if (variable->_type == TCInt32)
{
int32_t newValue = CFSwapInt32HostToBig(*((int32_t *)buffer));
memcpy(buffer, &newValue, sizeof(int32_t));
}
else if (variable->_type == TCInt64)
{
int64_t newValue = CFSwapInt64HostToBig(*((int64_t *)buffer));
memcpy(buffer, &newValue, sizeof(int64_t));
}
else if (variable->_type == TCFloat)
{
CFSwappedFloat32 newValue = CFConvertFloat32HostToSwapped(*((float *)buffer));
memcpy(buffer, &(newValue.v), sizeof(float));
}
else if (variable->_type == TCDouble)
{
CFSwappedFloat64 newValue = CFConvertDoubleHostToSwapped(*((double *)buffer));
memcpy(buffer, &(newValue.v), sizeof(double));
}
}
}
- (unsigned)valueSize
{
return _size;
}
- (BOOL)isValueValid
{
return _isValueValid;
}
- (BOOL)isEnabled
{
return _enabled;
}
- (void)setEnabled:(BOOL)enabled
{
_enabled = enabled;
}
#if MAC_OS_X_VERSION_10_5 <= MAC_OS_X_VERSION_MAX_ALLOWED
- (NSInteger)tag
#else
- (int)tag
#endif
{
return _tag;
}
#if MAC_OS_X_VERSION_10_5 <= MAC_OS_X_VERSION_MAX_ALLOWED
- (void)setTag:(NSInteger)tag
#else
- (void)setTag:(int)tag
#endif
{
_tag = tag;
}
@end