/** EOAttribute.m
Returns the name of the class values of this attribute * are represented by. The standard classes are NSNumber, * NSString, NSData and NSDate for the corresponding * [adaptorValueType]. A model can define more specific * classes like NSDecimalNumber, NSCalendarDate and NSImage * or custom classes which implement a factory method * specified by [valueFactoryMethodName] to create instances * with the data supplied by the data source.
*If the valueClassName has not been set explicitly and the * reciever [isFlattened], the valueClassName of the flattened * attribute is returned.
*Otherwise, if the reciever has a prototype then the * valueClassName of the prototype is returned.
*If all that fails, this method returns nil.
*See also:[setValueClassName:]
*/ - (NSString *)valueClassName { if (_valueClassName) return _valueClassName; if ([self isFlattened]) return [[_definitionArray realAttribute] valueClassName]; return [_prototype valueClassName]; } /** *Returns the adaptor specific name of externalType. This is * the name use during SQL generation.
*If the externalType has not been set explicitly and the * reciever [isFlattened], the valueClassName of the flattened * attribute is returned.
*Otherwise, if the reciever has a prototype then the * externalType of the prototype is returned.
*If all that fails, this method returns nil.
*/ - (NSString *)externalType { if (_externalType) return _externalType; if ([self isFlattened]) return [[_definitionArray realAttribute] externalType]; return [_prototype externalType]; } /** *Returns a one character string identifiying the underlying * C type of an NSNumber [valueTypeName]. The legal values in GDL2 are:
*If the valueType has not been set explicitly and the * reciever [isFlattened], the valueClassName of the flattened * attribute is returned.
*Otherwise, if the reciever has a prototype then the * valueType of the prototype is returned.
*If all that fails, this method returns nil.
*/ - (NSString *)valueType { if (_valueType) return _valueType; else if([self isFlattened]) return [[_definitionArray realAttribute] valueType]; else return [_prototype valueType]; } @end @implementation EOAttribute (EOAttributeSQLExpression) /** * Returns the value to use in an EOSQLExpression. **/ - (NSString *) valueForSQLExpression: (EOSQLExpression *)sqlExpression { NSString *value=nil; // EOFLOGObjectLevel(@"gsdb",@"EOAttribute %p",self); NSEmitTODO(); //TODO if (_definitionArray) value = [_definitionArray valueForSQLExpression: sqlExpression]; else value = [self name]; return value; } @end @implementation EOAttribute (EOAttributeEditing) - (NSException *)validateName:(NSString *)name { NSArray *storedProcedures; const char *p, *s = [name cString]; int exc = 0; if ([_name isEqual:name]) return nil; if (!name || ![name length]) exc++; if (!exc) { p = s; while (*p) { if (!isalnum(*p) && *p != '@' && *p != '#' && *p != '_' && *p != '$') { exc++; break; } p++; } if (!exc && *s == '$') exc++; if (exc) return [NSException exceptionWithName: NSInvalidArgumentException reason: [NSString stringWithFormat:@"%@ -- %@ 0x%x: argument \"%@\" contains invalid char '%c'", NSStringFromSelector(_cmd), NSStringFromClass([self class]), self, name, *p] userInfo: nil]; if ([[self entity] attributeNamed:name]) exc++; else if ((storedProcedures = [[[self entity] model] storedProcedures])) { NSEnumerator *stEnum = [storedProcedures objectEnumerator]; EOStoredProcedure *st; while ((st = [stEnum nextObject])) { NSEnumerator *attrEnum; EOAttribute *attr; attrEnum = [[st arguments] objectEnumerator]; while ((attr = [attrEnum nextObject])) { if ([name isEqualToString: [attr name]]) { exc++; break; } } if (exc) break; } } } if (exc) { return [NSException exceptionWithName: NSInvalidArgumentException reason: [NSString stringWithFormat: @"%@ -- %@ 0x%x: \"%@\" already used in the model", NSStringFromSelector(_cmd), NSStringFromClass([self class]), self, name] userInfo: nil]; } return nil; } - (void)setName: (NSString *)name { if ([_name isEqual: name]==NO) { NSString *oldName = nil; [[self validateName: name] raise]; oldName = AUTORELEASE(RETAIN(_name)); [self willChange]; ASSIGN(_name, name); if (_flags.isParentAnEOEntity) { [_parent _setIsEdited]; [_parent _attributeNameChangedFrom: oldName to: name]; } } } - (void)setPrototype: (EOAttribute *)prototype { [self willChange]; ASSIGN(_prototype, prototype); } - (void)setColumnName: (NSString *)columnName { //seems OK [self willChange]; ASSIGN(_columnName, columnName); DESTROY(_definitionArray); [_parent _setIsEdited]; [self _setOverrideForKeyEnum:1]; } - (void)_setDefinitionWithoutFlushingCaches: (NSString *)definition { EOExpressionArray *expressionArray=nil; [self willChange]; expressionArray = [_parent _parseDescription: definition isFormat: NO arguments: NULL]; expressionArray = [self _normalizeDefinition: expressionArray path: nil]; /* //TODO finish l un est code entity primaryKeyAttributes (code) ?? [self _removeFromEntityArray:code selector:setPrimaryKeyAttributes: */ ASSIGN(_definitionArray, expressionArray); } -(id)_normalizeDefinition: (EOExpressionArray*)definition path: (id)path { //TODO /* definition _isPropertyPath //NO count object atindex self _normalizeDefinition:ret path:NSArray() adddobject if attribute if isderived //NO ?? ret attr return nexexp */ return definition; } - (void)setDefinition:(NSString *)definition { if(definition) { [self willChange]; [self _setDefinitionWithoutFlushingCaches: definition]; [_parent _setIsEdited]; DESTROY(_columnName);//?? } } - (void)setReadOnly: (BOOL)yn { if(!yn && ([self isDerived] && ![self isFlattened])) [NSException raise: NSInvalidArgumentException format: @"%@ -- %@ 0x%x: cannot set to NO while the attribute is derived but not flattened.", NSStringFromSelector(_cmd), NSStringFromClass([self class]), self]; [self willChange]; _flags.isReadOnly = yn; } - (void)setExternalType: (NSString *)type { //OK [self willChange]; ASSIGN(_externalType, type); [_parent _setIsEdited]; [self _setOverrideForKeyEnum: 0];//TODO } - (void)setValueType: (NSString *)type { //OK [self willChange]; ASSIGN(_valueType, type); if ([_valueType length]==1) _valueTypeCharacter = [_valueType characterAtIndex:0]; else _valueTypeCharacter = '\0'; [self _setOverrideForKeyEnum: 4];//TODO } - (void)setValueClassName: (NSString *)name { [self willChange]; ASSIGN(_valueClassName, name); _valueClass = NSClassFromString(_valueClassName); _flags.isAttributeValueInitialized = NO; [self _setOverrideForKeyEnum: 3];//TODO } - (void)setWidth: (unsigned)length { [self willChange]; _width = length; } - (void)setPrecision: (unsigned)precision { [self willChange]; _precision = precision; } - (void)setScale: (int)scale { [self willChange]; _scale = scale; } - (void)setAllowsNull: (BOOL)allowsNull { //OK [self willChange]; _flags.allowsNull = allowsNull; [self _setOverrideForKeyEnum: 15];//TODO } - (void)setWriteFormat: (NSString *)string { [self willChange]; ASSIGN(_writeFormat, string); } - (void)setReadFormat: (NSString *)string { [self willChange]; ASSIGN(_readFormat, string); } - (void)setParameterDirection: (EOParameterDirection)parameterDirection { [self willChange]; _parameterDirection = parameterDirection; } - (void)setUserInfo: (NSDictionary *)dictionary { //OK [self willChange]; ASSIGN(_userInfo, dictionary); [_parent _setIsEdited]; [self _setOverrideForKeyEnum: 10];//TODO } - (void)setInternalInfo: (NSDictionary *)dictionary { //OK [self willChange]; ASSIGN(_internalInfo, dictionary); [_parent _setIsEdited]; [self _setOverrideForKeyEnum: 10]; //TODO } - (void)setDocComment: (NSString *)docComment { //OK [self willChange]; ASSIGN(_docComment, docComment); [_parent _setIsEdited]; } @end @implementation EOAttribute (EOBeautifier) /*+ Make the name conform to the Next naming style NAME -> name, FIRST_NAME -> firstName +*/ - (void)beautifyName { NSArray *listItems; NSString *newString=[NSMutableString string]; int anz,i; EOFLOGObjectFnStartOrCond2(@"ModelingClasses", @"EOAttribute"); // Makes the receiver's name conform to a standard convention. Names that conform to this style are all lower-case except for the initial letter of each embedded word other than the first, which is upper case. Thus, "NAME" becomes "name", and "FIRST_NAME" becomes "firstName". if ((_name) && ([_name length]>0)) { listItems = [_name componentsSeparatedByString: @"_"]; newString = [newString stringByAppendingString: [[listItems objectAtIndex: 0] lowercaseString]]; anz = [listItems count]; for(i = 1; i < anz; i++) { newString = [newString stringByAppendingString: [[listItems objectAtIndex: i] capitalizedString]]; } //#warning add all components (attributes, ...) // Exception abfangen NS_DURING { [self setName: newString]; } NS_HANDLER { NSLog(@"%@ in Class: EOAttribute , Method: beautifyName >> error : %@", [localException name], [localException reason]); } NS_ENDHANDLER; } EOFLOGObjectFnStopOrCond2(@"ModelingClasses", @"EOAttribute"); } @end @implementation EOAttribute (EOCalendarDateSupport) - (NSTimeZone *)serverTimeZone { if (_serverTimeZone) return _serverTimeZone; return [_prototype serverTimeZone]; } @end @implementation EOAttribute (EOCalendarDateSupportEditing) - (void)setServerTimeZone: (NSTimeZone *)tz { [self willChange]; ASSIGN(_serverTimeZone, tz); } @end @implementation EOAttribute (EOAttributeValueCreation) /** * Returns an NSData or a custom-class value object * from the supplied set of bytes. * The Adaptor calls this method during value creation * when fetching objects from the database. * For efficiency, the returned value is NOT autoreleased. * * NB: The documentation of the reference implementation * mistakenly claims that it returns an NSString. **/ - (id)newValueForBytes: (const void *)bytes length: (int)length { NSData *value = nil; Class valueClass = [self _valueClass]; if (valueClass != Nil && valueClass != GDL2_NSDataClass) { switch (_argumentType) { case EOFactoryMethodArgumentIsNSData: { //For efficiency reasons, the returned value is NOT autoreleased ! value = [GDL2_alloc(NSData) initWithBytes: bytes length: length]; // If we have a value factiry method, call it to get the final value if(_valueFactoryMethod != NULL) { NSData* tmp = value; // valueFactoryMethod returns an autoreleased value value = [(id)valueClass performSelector: _valueFactoryMethod withObject: value]; if (value != tmp) { RETAIN(value); RELEASE(tmp); }; }; break; } case EOFactoryMethodArgumentIsBytes: { NSMethodSignature *aSignature = nil; NSInvocation *anInvocation = nil; // TODO: verify with WO NSAssert2(_valueFactoryMethod, @"No _valueFactoryMethod (valueFactoryMethodName=%@) in attribute %@", _valueFactoryMethodName,self); // First find signature for method aSignature = [valueClass methodSignatureForSelector: _valueFactoryMethod]; // Create the invocation object anInvocation = [NSInvocation invocationWithMethodSignature: aSignature]; // Put the selector [anInvocation setSelector: _valueFactoryMethod]; // The target is the custom value class [anInvocation setTarget: valueClass]; // arguments are buffer pointer and length [anInvocation setArgument: &bytes atIndex: 2]; [anInvocation setArgument: &length atIndex: 3]; // Let's invoke the method [anInvocation invoke]; // Get the returned value [anInvocation getReturnValue: &value]; //For efficiency reasons, the returned value is NOT autoreleased ! // valueFactoryMethod returns an autoreleased value RETAIN(value); break; } case EOFactoryMethodArgumentIsNSString: // TODO: verify with WO break; } } if(!value) { //For efficiency reasons, the returned value is NOT autoreleased ! value = [GDL2_alloc(NSData) initWithBytes: bytes length: length]; } return value; } /** * Returns a NSString or a custom-class value object * from the supplied set of bytes using encoding. * The Adaptor calls this method during value creation * when fetching objects from the database. * For efficiency, the returned value is NOT autoreleased. **/ - (id)newValueForBytes: (const void *)bytes length: (int)length encoding: (NSStringEncoding)encoding { NSString* value = nil; Class valueClass = [self _valueClass]; if (valueClass != Nil && valueClass != GDL2_NSStringClass) { switch (_argumentType) { case EOFactoryMethodArgumentIsNSString: { NSData *data = nil; NSString *string = nil; data = AUTORELEASE([(GDL2_alloc(NSData)) initWithBytes: bytes length: length]); string = [(GDL2_alloc(NSString)) initWithData: data encoding: encoding]; // If we have a value factiry method, call it to get the final value if(_valueFactoryMethod != NULL) { value = [((id)valueClass) performSelector: _valueFactoryMethod withObject: string]; if ( value != string) { //For efficiency reasons, the returned value is NOT autoreleased ! RETAIN(value); RELEASE(string); }; } else { //For efficiency reasons, the returned value is NOT autoreleased ! value = string; }; break; } case EOFactoryMethodArgumentIsBytes: { NSMethodSignature *aSignature = nil; NSInvocation *anInvocation = nil; // TODO: verify with WO NSAssert2(_valueFactoryMethod, @"No _valueFactoryMethod (valueFactoryMethodName=%@) in attribute %@", _valueFactoryMethodName,self); // First find signature for method aSignature = [valueClass methodSignatureForSelector: _valueFactoryMethod]; // Create the invocation object anInvocation = [NSInvocation invocationWithMethodSignature: aSignature]; // Put the selector [anInvocation setSelector: _valueFactoryMethod]; // The target is the custom value class [anInvocation setTarget: valueClass]; // arguments are buffer pointer, length and encoding [anInvocation setArgument: &bytes atIndex: 2]; [anInvocation setArgument: &length atIndex: 3]; [anInvocation setArgument: &encoding atIndex: 4]; // Let's invoke the method [anInvocation invoke]; // Get the returned value [anInvocation getReturnValue: &value]; //For efficiency reasons, the returned value is NOT autoreleased ! // valueFactoryMethod returns an autoreleased value RETAIN(value); break; } case EOFactoryMethodArgumentIsNSData: // TODO: verify with WO break; } } if(!value) { NSData *data; data = AUTORELEASE([(GDL2_alloc(NSData)) initWithBytes: bytes length: length]); //For efficiency reasons, the returned value is NOT autoreleased ! value = [(GDL2_alloc(NSString)) initWithData: data encoding: encoding]; } return value; } /** * Returns an NSCalendarDate object * from the supplied time information. * The Adaptor calls this method during value creation * when fetching objects from the database. * For efficiency, the returned value is NOT autoreleased. * Milliseconds are dropped since they cannot be easily be stored in * NSCalendarDate. **/ - (NSCalendarDate *)newDateForYear: (int)year month: (unsigned)month day: (unsigned)day hour: (unsigned)hour minute: (unsigned)minute second: (unsigned)second millisecond: (unsigned)millisecond timezone: (NSTimeZone *)timezone zone: (NSZone *)zone { NSCalendarDate *date = nil; // FIXME: extend initializer to include Milliseconds //For efficiency reasons, the returned value is NOT autoreleased ! date = [(GDL2_allocWithZone(NSCalendarDate,zone)) initWithYear: year month: month day: day hour: hour minute: minute second: second timeZone: timezone]; return date; } /** Returns the name of the method to use for creating a custom class value for this attribute. See Also: - valueFactoryMethod, -newValueForBytes:length: **/ - (NSString *)valueFactoryMethodName { return _valueFactoryMethodName; } /** Returns the selector of the method to use for creating a custom class value for this attribute. Default implementation returns selector for name returned by -valueFactoryMethodName or NULL if no selector is found. See Also: - valueFactoryMethodName, -newValueForBytes:length: **/ - (SEL)valueFactoryMethod { return _valueFactoryMethod; } /** * Depending on -adaptorValueType this method checks whether the value * is a NSNumber, NSString, NSData or NSDate instance respectively. * If not, it attempts to retrieve the -adaptorValueConversionMethod * which should be used to convert the value accordingly. If none * has been specified and the -adaptorValueType is EOAdaptorBytesType, * it tries to convert the value by invoking -archiveData. * The EONull instance is not converted. * Returns the converted value. * Note: This implementation currently raises if -adaptorValueType is of * an unknown type or if conversion is necessary but not possible. This * maybe contrary to the reference implementation but it seems like useful * behavior. If this is causing problems please submit a bug report. */ - (id)adaptorValueByConvertingAttributeValue: (id)value { EOAdaptorValueType adaptorValueType = [self adaptorValueType]; // No conversion for an EONull value if (value != GDL2_EONull) { BOOL convert = NO; // Find if we need a conversion switch (adaptorValueType) { case EOAdaptorNumberType: convert = [value isKindOfClass: GDL2_NSNumberClass] ? NO : YES; break; case EOAdaptorCharactersType: convert = [value isKindOfClass: GDL2_NSStringClass] ? NO : YES; break; case EOAdaptorBytesType: convert = [value isKindOfClass: GDL2_NSDataClass] ? NO : YES; break; case EOAdaptorDateType: convert = [value isKindOfClass: GDL2_NSDateClass] ? NO : YES; break; default: [NSException raise: NSInvalidArgumentException format: @"Illegal adaptorValueType: %d", adaptorValueType]; } // Do value need conversion ? if (convert) { SEL sel; sel = [self adaptorValueConversionMethod]; if (sel == 0) { if (adaptorValueType == EOAdaptorBytesType) { value = [value archiveData]; } else { /* This exception might not be conformant, but seems helpful. */ [NSException raise: NSInvalidArgumentException format: @"Value of class: %@ needs conversion " @"yet no conversion method specified. " @"Attribute is %@. adaptorValueType=%d", NSStringFromClass([value class]), self,adaptorValueType]; } } else { value = [value performSelector: sel]; } } }; return value; } /** Returns method name to use to convert value of a class different than attribute adaptor value type. See also: -adaptorValueByConvertingAttributeValue, -adaptorValueConversionMethod **/ - (NSString *)adaptorValueConversionMethodName { return _adaptorValueConversionMethodName; } /** Returns selector of the method to use to convert value of a class different than attribute adaptor value type. Default implementation returns selector of method returned by adaptorValueConversionMethodName or NULL if there's not selector for the method See also: -adaptorValueByConvertingAttributeValue, -adaptorValueConversionMethodName **/ - (SEL)adaptorValueConversionMethod { return _adaptorValueConversionMethod; } /** Returns an EOAdaptorValueType describing the adaptor (i.e. database) type of data for this attribute. Returned value can be: EOAdaptorBytesType Raw bytes (default type) EOAdaptorNumberType Number value (attribute valueClass is kind of NSNumber) EOAdaptorCharactersType String value (attribute valueClass is kind of NSString) EOAdaptorDateType Date value (attribute valueClass is kind of NSDate) **/ - (EOAdaptorValueType)adaptorValueType { if (!_flags.isAttributeValueInitialized) { Class adaptorClasses[] = { GDL2_NSNumberClass, GDL2_NSStringClass, GDL2_NSDateClass }; EOAdaptorValueType values[] = { EOAdaptorNumberType, EOAdaptorCharactersType, EOAdaptorDateType }; Class valueClass = Nil; int i = 0; _adaptorValueType = EOAdaptorBytesType; for ( i = 0; i < 3 && !_flags.isAttributeValueInitialized; i++) { for ( valueClass = [self _valueClass]; valueClass != Nil; valueClass = GSObjCSuper(valueClass)) { if (valueClass == adaptorClasses[i]) { _adaptorValueType=values[i]; _flags.isAttributeValueInitialized = YES; break; } } } _flags.isAttributeValueInitialized = YES; }; return _adaptorValueType; } /** Returns the type of argument needed by the factoryMethod. Type can be: EOFactoryMethodArgumentIsNSData method need one parameter: a NSData EOFactoryMethodArgumentIsNSString method need one parameter: a NSString EOFactoryMethodArgumentIsBytes method need 2 parameters (for data type valueClass): a raw bytes buffer and its length or 3 parameters (for string type valueClass): a raw bytes buffer, its length and the encoding See also: -valueFactoryMethod, -setFactoryMethodArgumentType: **/ - (EOFactoryMethodArgumentType)factoryMethodArgumentType { return _argumentType; } @end @implementation EOAttribute (EOAttributeValueCreationEditing) /** Set the "factory method" name (the method to invoke to create custom class attribute value). This method must be a class method returning an autoreleased value of attribute valueClass. See also: -setFactoryMethodArgumentType: **/ - (void)setValueFactoryMethodName: (NSString *)factoryMethodName { [self willChange]; ASSIGN(_valueFactoryMethodName, factoryMethodName); _valueFactoryMethod = NSSelectorFromString(_valueFactoryMethodName); } /** Set method name to use to convert value of a class different than attribute adaptor value type. See also: -adaptorValueByConvertingAttributeValue, -adaptorValueConversionMethod, -adaptorValueConversionMethodName **/ - (void)setAdaptorValueConversionMethodName: (NSString *)conversionMethodName { [self willChange]; ASSIGN(_adaptorValueConversionMethodName, conversionMethodName); _adaptorValueConversionMethod = NSSelectorFromString(_adaptorValueConversionMethodName); } /** Set the type of argument needed by the factoryMethod. Type can be: EOFactoryMethodArgumentIsNSData method need one parameter: a NSData EOFactoryMethodArgumentIsNSString method need one parameter: a NSString EOFactoryMethodArgumentIsBytes method need 2 parameters (for data type valueClass): a raw bytes buffer and its length or 3 parameters (for string type valueClass): a raw bytes buffer, its length and the encoding See also: -setValueFactoryMethodName:, -factoryMethodArgumentType **/ - (void)setFactoryMethodArgumentType: (EOFactoryMethodArgumentType)argumentType { [self willChange]; _argumentType = argumentType; } @end @implementation EOAttribute (EOAttributeValueMapping) /** Validates value pointed by valueP, may set changed validated value in valueP and return an validation exception if constraints validation fails. valueP must not be NULL. More details: 1. raise an exception if [self allowsNull] == NO but *valueP is nil or EONull except if attribute is a primaryKey attribute (reason of this process exception is currently unknown). 2. if valueClassName isn't set, return nil and leave *valueP unchanged 3. if it can't find the class by name, log message, return nil and leave *valueP unchanged 4. do the fancy type conversions as necessary (Pretty much the current handling we have) 5. THEN if width is not 0 call adaptorValueByConvertingAttributeValue: on the new value and the if returned value is NSString or NSData validate length with width and return a corresponding exception if it's longer than allowed. **/ - (NSException *)validateValue: (id*)valueP { NSException *exception=nil; EOFLOGObjectFnStart(); NSAssert(valueP, @"No value pointer"); NSDebugMLog(@"In EOAttribute validateValue: value (class=%@) = %@ attribute = %@", [*valueP class],*valueP,self); // First check if value is nil or EONull if (_isNilOrEONull(*valueP)) { // Check if this is not allowed if ([self allowsNull] == NO) { NSArray *pkAttributes = [[self entity] primaryKeyAttributes]; // "Primary key attributes are ignored when enforcing allowsNull // property for attributes. The values could be handled later // by automatic PK-generation later if ([pkAttributes indexOfObjectIdenticalTo: self] == NSNotFound) { exception = [NSException validationExceptionWithFormat: @"attribute '%@' of entity '%@' cannot be nil or EONull ", [self name],[[self entity] name]]; }; } } else // There's a value. { NSString* valueClassName=[self valueClassName]; // if there's no valueClassName, leave the value unchanged // and don't return an exception if (valueClassName) { Class valueClass=[self _valueClass]; // There's a className but no class ! if (!valueClass) { //Log this problem, leave the value unchanged // and don't return an exception NSLog(@"No valueClass for valueClassName '%@' in attribute %@", valueClassName,self); } else { unsigned int width = 0; IMP isKindOfClassIMP=[*valueP methodForSelector:@selector(isKindOfClass:)]; // If the value has not the good class we'll try to convert it if ((*isKindOfClassIMP)(*valueP,@selector(isKindOfClass:), valueClass) == NO) { // Is it a string ? if ((*isKindOfClassIMP)(*valueP,@selector(isKindOfClass:), GDL2_NSStringClass)) { if (valueClass == GDL2_NSNumberClass) { unichar valueTypeCharacter = [self _valueTypeCharacter]; switch(valueTypeCharacter) { case 'i': *valueP = [GDL2_alloc(NSNumber) initWithInt: [*valueP intValue]]; AUTORELEASE(*valueP); break; case 'I': *valueP = [GDL2_alloc(NSNumber) initWithUnsignedInt: [*valueP unsignedIntValue]]; AUTORELEASE(*valueP); break; case 'c': *valueP = [GDL2_alloc(NSNumber) initWithChar: [*valueP intValue]]; AUTORELEASE(*valueP); break; case 'C': *valueP = [GDL2_alloc(NSNumber) initWithUnsignedChar: [*valueP unsignedIntValue]]; AUTORELEASE(*valueP); break; case 's': *valueP = [GDL2_alloc(NSNumber) initWithShort: [*valueP shortValue]]; AUTORELEASE(*valueP); break; case 'S': *valueP = [GDL2_alloc(NSNumber) initWithUnsignedShort: [*valueP unsignedShortValue]]; AUTORELEASE(*valueP); break; case 'l': *valueP = [GDL2_alloc(NSNumber) initWithLong: [*valueP longValue]]; AUTORELEASE(*valueP); break; case 'L': *valueP = [GDL2_alloc(NSNumber) initWithUnsignedLong: [*valueP unsignedLongValue]]; AUTORELEASE(*valueP); break; case 'u': *valueP = [GDL2_alloc(NSNumber) initWithLongLong: [*valueP longLongValue]]; AUTORELEASE(*valueP); break; case 'U': *valueP = [GDL2_alloc(NSNumber) initWithUnsignedLongLong: [*valueP unsignedLongLongValue]]; AUTORELEASE(*valueP); break; case 'f': *valueP = [GDL2_alloc(NSNumber) initWithFloat: [*valueP floatValue]]; AUTORELEASE(*valueP); break; default: *valueP = [GDL2_alloc(NSNumber) initWithDouble: [*valueP doubleValue]]; AUTORELEASE(*valueP); break; }; } else if (valueClass == GDL2_NSDecimalNumberClass) { *valueP = [GDL2_alloc(NSDecimalNumber) initWithString: *valueP]; AUTORELEASE(*valueP); } else if (valueClass == GDL2_NSDataClass) { //TODO Verify here. *valueP = [*valueP dataUsingEncoding: [NSString defaultCStringEncoding]]; } else if (valueClass == GDL2_NSCalendarDateClass) { *valueP = AUTORELEASE([(GDL2_alloc(NSCalendarDate)) initWithString: *valueP]); } } }; // Now, test width if any width = [self width]; if (width>0) { // First convert value to adaptor value id testValue = [self adaptorValueByConvertingAttributeValue: *valueP]; if (testValue) { IMP testIsKindOfClassIMP=[testValue methodForSelector:@selector(isKindOfClass:)]; // We can test NSString and NSData type only if ((*testIsKindOfClassIMP)(testValue,@selector(isKindOfClass:), GDL2_NSStringClass) || (*testIsKindOfClassIMP)(testValue,@selector(isKindOfClass:), GDL2_NSDataClass)) { unsigned int testValueLength = [testValue length]; if (testValueLength > width) { exception = [NSException validationExceptionWithFormat: @"Value %@ for attribute '%@' is too large", testValue,[self name]]; }; }; }; }; } } } EOFLOGObjectFnStop(); return exception; } @end @implementation NSObject (EOCustomClassArchiving) + objectWithArchiveData: (NSData *)data { return [NSUnarchiver unarchiveObjectWithData:data]; } - (NSData *)archiveData { return [NSArchiver archivedDataWithRootObject:self]; } @end @implementation EOAttribute (EOAttributePrivate) - (void)setParent: (id)parent { //OK [self willChange]; _parent = parent; _flags.isParentAnEOEntity = [_parent isKindOfClass: [EOEntity class]];//?? } - (EOAttribute *)realAttribute { return _realAttribute; } - (NSMutableArray *)_definitionArray { return _definitionArray; } - (Class)_valueClass { if (_valueClass) return _valueClass; else if ([self isFlattened]) return [[_definitionArray realAttribute] _valueClass]; else return [_prototype _valueClass]; } /* * This method returns the valueType as a unichar character. * The value of the instance variable get set implicitly * if the valueType is set explicitly with a legal value. * Otherwise the effective valueType of reciever is used. * TODO: Once this has been set later implicit changes to the * valueType via flattend attrubutes or prototypes will not * be honored. Value validation can be a hot spot so this method * (or rather it's only use in validateValue:) should remain efficient. */ - (unichar)_valueTypeCharacter { unichar valueTypeCharacter = _valueTypeCharacter; if (valueTypeCharacter == '\0') { NSString* valueType = [self valueType]; if ([valueType length] == 1) valueTypeCharacter = [valueType characterAtIndex:0]; } return valueTypeCharacter; }; @end @implementation EOAttribute (EOAttributePrivate2) - (BOOL) _hasAnyOverrides { [self notImplemented: _cmd]; //TODO return NO; } - (void) _resetPrototype { [self notImplemented: _cmd]; //TODO } - (void) _updateFromPrototype { [self notImplemented: _cmd]; //TODO } - (void) _setOverrideForKeyEnum: (int)keyEnum { //[self notImplemented:_cmd]; //TODO } - (BOOL) _isKeyEnumOverriden: (int)param0 { [self notImplemented: _cmd]; //TODO return NO; } - (BOOL) _isKeyEnumDefinedByPrototype: (int)param0 { [self notImplemented: _cmd]; //TODO return NO; } @end