1/*
2  Copyright (C) 2000-2005 SKYRIX Software AG
3
4  This file is part of SOPE.
5
6  SOPE is free software; you can redistribute it and/or modify it under
7  the terms of the GNU Lesser General Public License as published by the
8  Free Software Foundation; either version 2, or (at your option) any
9  later version.
10
11  SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12  WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14  License for more details.
15
16  You should have received a copy of the GNU Lesser General Public
17  License along with SOPE; see the file COPYING.  If not, write to the
18  Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19  02111-1307, USA.
20*/
21
22#include "EOClassDescription.h"
23#include "EOKeyValueCoding.h"
24#include "EONull.h"
25#include "common.h"
26
27#if !LIB_FOUNDATION_LIBRARY
28
29@interface NSException(UsedSetUI) /* does Jaguar allow -setUserInfo: ? */
30- (void)setUserInfo:(NSDictionary *)_ui;
31@end
32
33#endif
34
35@implementation NSClassDescription(EOValidation)
36
37- (NSException *)validateObjectForDelete:(id)_object {
38  return nil;
39}
40- (NSException *)validateObjectForSave:(id)_object {
41  return nil;
42}
43- (NSException *)validateValue:(id *)_value forKey:(NSString *)_key {
44  return nil;
45}
46
47@end /* NSClassDescription(EOValidation) */
48
49@implementation NSObject(EOValidation)
50
51- (NSException *)validateForDelete {
52  return [[self classDescription] validateObjectForDelete:self];
53}
54
55- (NSException *)validateForInsert {
56  return [self validateForSave];
57}
58- (NSException *)validateForUpdate {
59  return [self validateForSave];
60}
61
62- (NSException *)validateForSave {
63  NSException    *e;
64  NSMutableArray *exceptions;
65  NSArray        *properties;
66  unsigned int i, count;
67  id (*validate)(id, SEL, id *, NSString *);
68  id (*objAtIdx)(id, SEL, unsigned int idx);
69  id (*valForKey)(id, SEL, NSString *);
70
71  exceptions = nil;
72
73  /* first ask class description to validate object */
74
75  if ((e = [[self classDescription] validateObjectForSave:self])) {
76    if (exceptions == nil) exceptions = [NSMutableArray array];
77    [exceptions addObject:e];
78  }
79
80  /* then process all properties */
81
82  if ((properties = [self allPropertyKeys]) == nil)
83    properties = [NSArray array];
84
85  validate  = (void *)[self methodForSelector:@selector(validateValue:forKey:)];
86  valForKey = (void *)[self methodForSelector:@selector(valueForKey:)];
87  objAtIdx  = (void *)[properties methodForSelector:@selector(objectAtIndex:)];
88
89  for (i = 0, count = [properties count]; i < count; i++) {
90    NSString *key;
91    id value, orgValue;
92
93    key      = objAtIdx(properties, @selector(objectAtIndex:), i);
94    orgValue = value = valForKey(self, @selector(valueForKey:), key);
95
96    if ((e = validate(self, @selector(validateValue:forKey:), &value, key))) {
97      /* validation of property failed */
98      if (exceptions == nil) exceptions = [NSMutableArray array];
99      [exceptions addObject:e];
100    }
101    else if (orgValue != value) {
102      /* the value was changed during validation */
103      [self takeValue:value forKey:key];
104    }
105  }
106
107  if ((count = [exceptions count]) == 0) {
108    return nil;
109  }
110  else if (count == 1) {
111    return [exceptions objectAtIndex:0];
112  }
113  else {
114    NSException *master;
115    NSMutableDictionary *ui;
116
117    master = [exceptions objectAtIndex:0];
118    [exceptions removeObjectAtIndex:0];
119    ui = [[master userInfo] mutableCopy];
120    if (ui == nil) ui = [[NSMutableDictionary alloc] init];
121    [ui setObject:exceptions forKey:@"EOAdditionalExceptions"];
122    [master setUserInfo:ui];
123    [ui release]; ui = nil;
124    return master;
125  }
126}
127
128- (NSException *)validateValue:(id *)_value forKey:(NSString *)_key {
129  NSException *e;
130
131  if ((e = [[self classDescription] validateValue:_value forKey:_key]))
132    return e;
133
134  /* should invoke key-specific methods, eg -validateBlah: */
135
136  {
137    /* construct 'validate'(8) + key + ':'(1) */
138    unsigned len;
139    char *buf;
140    SEL  sel;
141
142    len = [_key cStringLength];
143    buf = malloc(len + 14);
144    strcpy(buf, "validate");
145    [_key getCString:&buf[8]];
146    strcat(buf, ":");
147    buf[8] = toupper(buf[8]);
148
149    sel = sel_registerName(buf);
150    if (sel) {
151      if ([self respondsToSelector:sel]) {
152        if (buf) free(buf);
153        return [self performSelector:sel withObject:*_value];
154      }
155    }
156    if (buf) free(buf);
157  }
158  return nil;
159}
160
161@end /* NSObject(EOValidation) */
162