Create application/directory for subdir, if metadata or permissions are applied.
[pithos-ios] / Classes / NSObject+NSCoding.m
1 //
2 //  NSObject+NSCoding.m
3 //  OpenStack
4 //
5 //  Created by Michael Mayo on 3/4/11.
6 //  The OpenStack project is provided under the Apache 2.0 license.
7 //
8
9 #import "NSObject+NSCoding.h"
10 #import <objc/runtime.h>
11 //#import <objc/objc-class.h>
12
13
14 @implementation NSObject (NSCoding)
15
16 - (NSMutableDictionary *)propertiesForClass:(Class)klass {
17     
18     NSMutableDictionary *results = [[[NSMutableDictionary alloc] init] autorelease];
19     
20     unsigned int outCount, i;
21     objc_property_t *properties = class_copyPropertyList(klass, &outCount);
22     for(i = 0; i < outCount; i++) {
23         objc_property_t property = properties[i];
24         
25         NSString *pname = [NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
26         NSString *pattrs = [NSString stringWithCString:property_getAttributes(property) encoding:NSUTF8StringEncoding];
27         
28         pattrs = [[pattrs componentsSeparatedByString:@","] objectAtIndex:0];
29         pattrs = [pattrs substringFromIndex:1];
30         
31         [results setObject:pattrs forKey:pname];
32     }
33     free(properties);
34     
35     if ([klass superclass] != [NSObject class]) {
36         [results addEntriesFromDictionary:[self propertiesForClass:[klass superclass]]];
37     }
38     
39     return results;
40 }
41
42 - (NSDictionary *)properties {
43     return [self propertiesForClass:[self class]];
44 }
45
46 - (void)autoEncodeWithCoder:(NSCoder *)coder {
47     NSDictionary *properties = [self properties];
48     for (NSString *key in properties) {
49         NSString *type = [properties objectForKey:key];
50         id value;
51         unsigned long long ullValue;
52         BOOL boolValue;
53         float floatValue;
54         double doubleValue;
55         NSInteger intValue;
56         unsigned long ulValue;
57         NSString *className;
58
59         NSMethodSignature *signature = [self methodSignatureForSelector:NSSelectorFromString(key)];
60         NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
61         [invocation setSelector:NSSelectorFromString(key)];
62         [invocation setTarget:self];
63         
64         switch ([type characterAtIndex:0]) {
65             case '@':   // object
66                 if ([[type componentsSeparatedByString:@"\""] count] > 1) {
67                     className = [[type componentsSeparatedByString:@"\""] objectAtIndex:1];
68                     value = [self performSelector:NSSelectorFromString(key)];
69
70                     // only decode if the property conforms to NSCoding
71                     if (class_conformsToProtocol(NSClassFromString(className), @protocol(NSCoding))) {
72                         [coder encodeObject:value forKey:key];
73                     }
74                 }
75                 break;
76             case 'c':   // bool
77                 [invocation invoke];
78                 [invocation getReturnValue:&boolValue];
79                 [coder encodeObject:[NSNumber numberWithBool:boolValue] forKey:key];
80                 break;
81             case 'f':   // float
82                 [invocation invoke];
83                 [invocation getReturnValue:&floatValue];
84                 [coder encodeObject:[NSNumber numberWithFloat:floatValue] forKey:key];
85                 break;
86             case 'd':   // double
87                 [invocation invoke];
88                 [invocation getReturnValue:&doubleValue];
89                 [coder encodeObject:[NSNumber numberWithDouble:doubleValue] forKey:key];
90                 break;
91             case 'i':   // int
92                 [invocation invoke];
93                 [invocation getReturnValue:&intValue];
94                 [coder encodeObject:[NSNumber numberWithInt:intValue] forKey:key];
95                 break;
96             case 'L':   // unsigned long
97                 [invocation invoke];
98                 [invocation getReturnValue:&ulValue];
99                 [coder encodeObject:[NSNumber numberWithUnsignedLong:ulValue] forKey:key];
100                 break;
101             case 'Q':   // unsigned long long
102                 [invocation invoke];
103                 [invocation getReturnValue:&ullValue];
104                 [coder encodeObject:[NSNumber numberWithUnsignedLongLong:ullValue] forKey:key];
105                 break;
106             default:
107                 break;
108         }        
109     }
110 }
111
112 - (void)autoDecode:(NSCoder *)coder {
113     NSDictionary *properties = [self properties];
114     for (NSString *key in properties) {
115         NSString *type = [properties objectForKey:key];
116         id value;
117         NSNumber *number;
118         unsigned int addr;
119         NSInteger i;
120         CGFloat f;
121         BOOL b;
122         double d;
123         unsigned long ul;
124         unsigned long long ull;
125         Ivar ivar;
126         double *varIndex;        
127         NSString *className;
128         
129         switch ([type characterAtIndex:0]) {
130             case '@':   // object
131                 if ([[type componentsSeparatedByString:@"\""] count] > 1) {
132                     className = [[type componentsSeparatedByString:@"\""] objectAtIndex:1];                    
133                     // only decode if the property conforms to NSCoding
134                     if (class_conformsToProtocol(NSClassFromString(className), @protocol(NSCoding))) {
135                         value = [[coder decodeObjectForKey:key] retain];
136                         addr = (NSInteger)&value;
137                         object_setInstanceVariable(self, [key UTF8String], *(id**)addr);
138                     }
139                 }
140                 break;
141             case 'c':   // bool
142                 number = [coder decodeObjectForKey:key];                
143                 b = [number boolValue];
144                 addr = (NSInteger)&b;
145                 object_setInstanceVariable(self, [key UTF8String], *(NSInteger**)addr);
146                 break;
147             case 'f':   // float
148                 number = [coder decodeObjectForKey:key];                
149                 f = [number floatValue];
150                 addr = (NSInteger)&f;
151                 object_setInstanceVariable(self, [key UTF8String], *(NSInteger**)addr);
152                 break;
153             case 'd':   // double                
154                 number = [coder decodeObjectForKey:key];
155                 d = [number doubleValue];
156                 if ((ivar = class_getInstanceVariable([self class], [key UTF8String]))) {
157                     varIndex = (double *)(void **)((char *)self + ivar_getOffset(ivar));
158                     *varIndex = d;
159                 }
160                 break;
161             case 'i':   // int
162                 number = [coder decodeObjectForKey:key];
163                 i = [number intValue];
164                 addr = (NSInteger)&i;
165                 object_setInstanceVariable(self, [key UTF8String], *(NSInteger**)addr);
166                 break;
167             case 'L':   // unsigned long
168                 number = [coder decodeObjectForKey:key];
169                 ul = [number unsignedLongValue];
170                 addr = (NSInteger)&ul;
171                 object_setInstanceVariable(self, [key UTF8String], *(NSInteger**)addr);
172                 break;
173             case 'Q':   // unsigned long long
174                 number = [coder decodeObjectForKey:key];
175                 ull = [number unsignedLongLongValue];
176                 addr = (NSInteger)&ull;
177                 object_setInstanceVariable(self, [key UTF8String], *(NSInteger**)addr);
178                 break;
179             default:
180                 break;
181         }
182     }
183 }
184
185 - (NSInteger)intForKey:(NSString *)key inDict:(NSDictionary *)dict {
186     NSInteger result = 0;
187     if ([dict objectForKey:key] != [NSNull null]) {
188         result = [((NSNumber *)[dict objectForKey:key]) intValue];
189     }
190     return result;
191 }
192
193 - (void)autoParse:(NSObject **)object fromJSONDict:(NSDictionary *)dict {
194     NSDictionary *properties = [*object properties];
195     for (NSString *key in properties) {
196         
197         int i;        
198         
199         NSString *type = [properties objectForKey:key];
200         SEL setter = NSSelectorFromString([NSString stringWithFormat:@"set%@%@:", [[key uppercaseString] substringToIndex:1], [key substringFromIndex:1]]);
201         
202         NSMethodSignature *signature = [*object methodSignatureForSelector:setter];
203         NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
204         [invocation setSelector:setter];
205         [invocation setTarget:*object];
206         
207         switch ([type characterAtIndex:0]) {
208             case '@':   // object
209                 if ([[type componentsSeparatedByString:@"\""] count] > 1) {
210                     ///NSString *className = [[type componentsSeparatedByString:@"\""] objectAtIndex:1];
211                     [*object performSelector:setter withObject:[dict objectForKey:key]];
212                 }
213                 break;
214             case 'c':   // bool
215                 break;
216             case 'f':   // float
217                 break;
218             case 'd':   // double
219                 break;
220             case 'i':   // int
221                 if ([dict objectForKey:key]) {
222                     i = [*object intForKey:key inDict:dict];
223                     [invocation setArgument:&i atIndex:2];
224                     [invocation invoke];
225                 }
226                 break;
227             case 'L':   // unsigned long
228                 break;
229             case 'Q':   // unsigned long long
230                 break;
231             default:
232                 break;
233         }
234     }
235 }
236
237 @end