PageRenderTime 92ms CodeModel.GetById 14ms app.highlight 73ms RepoModel.GetById 1ms app.codeStats 0ms

/core/externals/update-engine/externals/google-toolbox-for-mac/Foundation/GTMNSAppleEventDescriptor+Foundation.m

http://macfuse.googlecode.com/
Objective C | 536 lines | 441 code | 61 blank | 34 comment | 52 complexity | 7e8908ed7e15d0bc0fb901d4660d10e0 MD5 | raw file
  1//
  2//  GTMNSAppleEventDescriptor+Foundation.m
  3//
  4//  Copyright 2008 Google Inc.
  5//
  6//  Licensed under the Apache License, Version 2.0 (the "License"); you may not
  7//  use this file except in compliance with the License.  You may obtain a copy
  8//  of the License at
  9// 
 10//  http://www.apache.org/licenses/LICENSE-2.0
 11// 
 12//  Unless required by applicable law or agreed to in writing, software
 13//  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 14//  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 15//  License for the specific language governing permissions and limitations under
 16//  the License.
 17//
 18
 19#import "GTMNSAppleEventDescriptor+Foundation.h"
 20#import "GTMDebugSelectorValidation.h"
 21#import <Carbon/Carbon.h>  // Needed Solely For keyASUserRecordFields
 22
 23// Map of types to selectors.
 24static NSMutableDictionary *gTypeMap = nil;
 25
 26@implementation NSAppleEventDescriptor (GTMAppleEventDescriptorArrayAdditions)
 27
 28+ (void)gtm_registerSelector:(SEL)selector 
 29                    forTypes:(DescType*)types 
 30                       count:(NSUInteger)count {
 31  if (selector && types && count > 0) {
 32#if DEBUG
 33    NSAppleEventDescriptor *desc 
 34      = [[[NSAppleEventDescriptor alloc] initListDescriptor] autorelease];
 35    GTMAssertSelectorNilOrImplementedWithReturnTypeAndArguments(desc, 
 36                                                                selector,
 37                                                                @encode(id), 
 38                                                                NULL); 
 39#endif
 40    @synchronized(self) {
 41      if (!gTypeMap) {
 42        gTypeMap = [[NSMutableDictionary alloc] init];
 43      }
 44      NSString *selString = NSStringFromSelector(selector);
 45      for (NSUInteger i = 0; i < count; ++i) {
 46        NSNumber *key = [NSNumber numberWithUnsignedInt:types[i]];
 47        NSString *exists = [gTypeMap objectForKey:key];
 48        if (exists) {
 49          _GTMDevLog(@"%@ being replaced with %@ exists for type: %@", 
 50                    exists, selString, key);
 51        }
 52        [gTypeMap setObject:selString forKey:key];
 53      }
 54    }
 55  }
 56}
 57
 58- (id)gtm_objectValue {
 59  id value = nil;
 60  
 61  // Check our registered types to see if we have anything
 62  if (gTypeMap) {
 63    @synchronized(gTypeMap) {
 64      DescType type = [self descriptorType];
 65      NSNumber *key = [NSNumber numberWithUnsignedInt:type];
 66      NSString *selectorString = [gTypeMap objectForKey:key];
 67      if (selectorString) {
 68        SEL selector = NSSelectorFromString(selectorString);
 69        value = [self performSelector:selector];
 70      } else {
 71        value = [self stringValue];
 72      }
 73    }
 74  }
 75  return value;
 76}
 77
 78- (NSArray*)gtm_arrayValue {
 79  NSUInteger count = [self numberOfItems];
 80  NSAppleEventDescriptor *workingDesc = self;
 81  if (count == 0) {
 82    // Create a list to work with.
 83    workingDesc = [self coerceToDescriptorType:typeAEList];
 84    count = [workingDesc numberOfItems];
 85  }
 86  NSMutableArray *items = [NSMutableArray arrayWithCapacity:count];
 87  for (NSUInteger i = 1; i <= count; ++i) {
 88    NSAppleEventDescriptor *desc = [workingDesc descriptorAtIndex:i];
 89    id value = [desc gtm_objectValue];
 90    if (!value) {
 91      _GTMDevLog(@"Unknown type of descriptor %@", [desc description]);
 92      return nil;
 93    }
 94    [items addObject:value];
 95  }
 96  return items;
 97}  
 98
 99- (NSDictionary*)gtm_dictionaryValue {
100  NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
101  NSAppleEventDescriptor *userRecord = [self descriptorForKeyword:keyASUserRecordFields];
102  if (userRecord) {
103    NSArray *userItems = [userRecord gtm_arrayValue];
104    NSString *key = nil;
105    NSString *item;
106    GTM_FOREACH_OBJECT(item, userItems) {
107      if (key) {
108        // Save the pair and reset our state
109        [dictionary setObject:item forKey:key];
110        key = nil;
111      } else {
112        // Save it for the next pair
113        key = item;
114      }
115    }
116    if (key) {
117      _GTMDevLog(@"Got a key %@ with no value in %@", key, userItems);
118      return nil;
119    }
120  } else {
121    NSUInteger count = [self numberOfItems];
122    for (NSUInteger i = 1; i <= count; ++i) {
123      AEKeyword key = [self keywordForDescriptorAtIndex:i];
124      NSAppleEventDescriptor *desc = [self descriptorForKeyword:key];
125      id value = [desc gtm_objectValue];
126      if (!value) {
127        _GTMDevLog(@"Unknown type of descriptor %@", [desc description]);
128        return nil;
129      }
130      [dictionary setObject:value 
131                     forKey:[GTMFourCharCode fourCharCodeWithFourCharCode:key]];
132    }
133  }
134  return dictionary;
135}  
136
137- (NSNull*)gtm_nullValue {
138  return [NSNull null];
139}
140
141+ (NSAppleEventDescriptor*)gtm_descriptorWithDouble:(double)real {
142  return [NSAppleEventDescriptor descriptorWithDescriptorType:typeIEEE64BitFloatingPoint
143                                                        bytes:&real 
144                                                       length:sizeof(real)];
145}
146
147+ (NSAppleEventDescriptor*)gtm_descriptorWithFloat:(float)real {
148  return [NSAppleEventDescriptor descriptorWithDescriptorType:typeIEEE32BitFloatingPoint
149                                                        bytes:&real 
150                                                       length:sizeof(real)];
151}
152
153
154+ (NSAppleEventDescriptor*)gtm_descriptorWithCGFloat:(CGFloat)real {
155#if CGFLOAT_IS_DOUBLE
156  return [self gtm_descriptorWithDouble:real];
157#else
158  return [self gtm_descriptorWithFloat:real];
159#endif
160}
161
162- (double)gtm_doubleValue {
163  // Be careful modifying this code as Xcode 3.2.5 gcc 4.2.1 (5664) was
164  // generating bad code with a previous incarnation.
165  NSNumber *number = [self gtm_numberValue];
166  if (number) {
167    return [number doubleValue];
168  }
169  return NAN;
170}
171
172- (float)gtm_floatValue {
173  NSNumber *number = [self gtm_numberValue];
174  if (number) {
175    return [number floatValue];
176  }
177  return NAN;
178}
179
180- (CGFloat)gtm_cgFloatValue {
181#if CGFLOAT_IS_DOUBLE
182  return [self gtm_doubleValue];
183#else
184  return [self gtm_floatValue];
185#endif
186}
187
188- (NSNumber*)gtm_numberValue { 
189  typedef struct {
190    DescType type;
191    SEL selector;
192  } TypeSelectorMap;
193  TypeSelectorMap typeSelectorMap[] = {
194    { typeFalse, @selector(numberWithBool:) },
195    { typeTrue, @selector(numberWithBool:) },
196    { typeBoolean, @selector(numberWithBool:) },
197    { typeSInt16, @selector(numberWithShort:) },
198    { typeSInt32, @selector(numberWithInt:) },
199    { typeUInt32, @selector(numberWithUnsignedInt:) },
200    { typeSInt64, @selector(numberWithLongLong:) },
201    { typeIEEE32BitFloatingPoint, @selector(numberWithFloat:) },
202    { typeIEEE64BitFloatingPoint, @selector(numberWithDouble:) }
203  };
204  DescType type = [self descriptorType];
205  SEL selector = nil;
206  for (size_t i = 0; i < sizeof(typeSelectorMap) / sizeof(TypeSelectorMap); ++i) {
207    if (type == typeSelectorMap[i].type) {
208      selector = typeSelectorMap[i].selector;
209      break;
210    }
211  }
212  NSAppleEventDescriptor *desc = self;
213  if (!selector) {
214    // COV_NF_START - Don't know how to force this in a unittest
215    _GTMDevLog(@"Didn't get a valid selector?");
216    desc = [self coerceToDescriptorType:typeIEEE64BitFloatingPoint];
217    selector = @selector(numberWithDouble:);
218    // COV_NF_END
219  }
220  NSData *descData = [desc data];
221  const void *bytes = [descData bytes];
222  if (!bytes) {
223    // COV_NF_START - Don't know how to force this in a unittest
224    _GTMDevLog(@"Unable to get bytes from %@", desc);
225    return nil;
226    // COV_NF_END
227  }
228  Class numberClass = [NSNumber class];
229  NSMethodSignature *signature = [numberClass methodSignatureForSelector:selector];
230  NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
231  [invocation setSelector:selector];
232  [invocation setArgument:(void*)bytes atIndex:2];
233  [invocation setTarget:numberClass];
234  [invocation invoke];
235  NSNumber *value = nil;
236  [invocation getReturnValue:&value];
237  return value;
238}
239
240- (GTMFourCharCode*)gtm_fourCharCodeValue {
241  return [GTMFourCharCode fourCharCodeWithFourCharCode:[self typeCodeValue]];
242}
243
244- (NSAppleEventDescriptor*)gtm_appleEventDescriptor {
245  return self;
246}
247
248@end
249
250@implementation NSObject (GTMAppleEventDescriptorObjectAdditions)
251- (NSAppleEventDescriptor*)gtm_appleEventDescriptor {
252  return [NSAppleEventDescriptor descriptorWithString:[self description]];
253}
254@end
255
256@implementation NSArray (GTMAppleEventDescriptorObjectAdditions)
257
258+ (void)load {
259  DescType types[] = { 
260    typeAEList,
261  };
262  
263  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
264  [NSAppleEventDescriptor gtm_registerSelector:@selector(gtm_arrayValue)
265                                     forTypes:types
266                                        count:sizeof(types)/sizeof(DescType)];
267  [pool drain];
268}
269
270- (NSAppleEventDescriptor*)gtm_appleEventDescriptor {
271  NSAppleEventDescriptor *desc = [NSAppleEventDescriptor listDescriptor];
272  NSUInteger count = [self count];
273  for (NSUInteger i = 1; i <= count; ++i) {
274    id item = [self objectAtIndex:i-1];
275    NSAppleEventDescriptor *itemDesc = [item gtm_appleEventDescriptor];
276    if (!itemDesc) {
277      _GTMDevLog(@"Unable to create Apple Event Descriptor for %@", [self description]);
278      return nil;
279    }
280    [desc insertDescriptor:itemDesc atIndex:i];
281  }
282  return desc;
283}
284@end
285
286@implementation NSDictionary (GTMAppleEventDescriptorObjectAdditions)
287
288+ (void)load {
289  DescType types[] = { 
290    typeAERecord,
291  };
292  
293  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
294  [NSAppleEventDescriptor gtm_registerSelector:@selector(gtm_dictionaryValue)
295                                    forTypes:types
296                                       count:sizeof(types)/sizeof(DescType)];
297  [pool drain];
298}
299
300- (NSAppleEventDescriptor*)gtm_appleEventDescriptor {
301  Class keyClass = nil;
302  id key = nil;
303  GTM_FOREACH_KEY(key, self) {
304    if (!keyClass) {
305      if ([key isKindOfClass:[GTMFourCharCode class]]) {
306        keyClass = [GTMFourCharCode class];
307      } else if ([key isKindOfClass:[NSString class]]) {
308        keyClass = [NSString class];
309      } else {
310        _GTMDevLog(@"Keys must be of type NSString or GTMFourCharCode: %@", key);
311        return nil;
312      }
313    }
314    if (![key isKindOfClass:keyClass]) {
315      _GTMDevLog(@"Keys must be homogenous (first key was of type %@) "
316                 "and of type NSString or GTMFourCharCode: %@", keyClass, key);
317      return nil;
318    }
319  }
320  NSAppleEventDescriptor *desc = [NSAppleEventDescriptor recordDescriptor];
321  if ([keyClass isEqual:[NSString class]]) {
322    NSMutableArray *array = [NSMutableArray arrayWithCapacity:[self count] * 2];
323    GTM_FOREACH_KEY(key, self) {
324      [array addObject:key];
325      [array addObject:[self objectForKey:key]];
326    }
327    NSAppleEventDescriptor *userRecord = [array gtm_appleEventDescriptor];
328    if (!userRecord) {
329      return nil;
330    }
331    [desc setDescriptor:userRecord forKeyword:keyASUserRecordFields];
332  } else {
333    GTM_FOREACH_KEY(key, self) {
334      id value = [self objectForKey:key];
335      NSAppleEventDescriptor *valDesc = [value gtm_appleEventDescriptor];
336      if (!valDesc) {
337        return nil;
338      }
339      [desc setDescriptor:valDesc forKeyword:[key fourCharCode]];
340    }
341  }
342  return desc;
343}
344
345@end
346
347@implementation NSNull (GTMAppleEventDescriptorObjectAdditions)
348+ (void)load {
349  DescType types[] = { 
350    typeNull
351  };
352  
353  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
354  [NSAppleEventDescriptor gtm_registerSelector:@selector(gtm_nullValue)
355                                      forTypes:types
356                                         count:sizeof(types)/sizeof(DescType)];
357  [pool drain];
358}
359
360- (NSAppleEventDescriptor*)gtm_appleEventDescriptor {
361  return [NSAppleEventDescriptor nullDescriptor];
362}
363@end
364
365@implementation NSString (GTMAppleEventDescriptorObjectAdditions)
366
367+ (void)load {
368  DescType types[] = { 
369    typeUTF16ExternalRepresentation,
370    typeUnicodeText,
371    typeUTF8Text,
372    typeCString,
373    typePString,
374    typeChar,
375    typeIntlText };
376  
377  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
378  [NSAppleEventDescriptor gtm_registerSelector:@selector(stringValue)
379                                      forTypes:types
380                                         count:sizeof(types)/sizeof(DescType)];
381  [pool drain];
382}
383
384- (NSAppleEventDescriptor*)gtm_appleEventDescriptor {
385  return [NSAppleEventDescriptor descriptorWithString:self];
386}
387@end
388
389@implementation NSNumber (GTMAppleEventDescriptorObjectAdditions)
390
391+ (void)load {
392  DescType types[] = { 
393    typeTrue,
394    typeFalse,
395    typeBoolean,
396    typeSInt16,
397    typeSInt32,
398    typeUInt32,
399    typeSInt64,
400    typeIEEE32BitFloatingPoint,
401    typeIEEE64BitFloatingPoint };
402  
403  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
404  [NSAppleEventDescriptor gtm_registerSelector:@selector(gtm_numberValue)
405                                     forTypes:types
406                                        count:sizeof(types)/sizeof(DescType)];
407  [pool drain];
408}
409
410- (NSAppleEventDescriptor*)gtm_appleEventDescriptor {
411  const char *type = [self objCType];
412  if (!type || strlen(type) != 1) return nil;
413  
414  DescType desiredType = typeNull;
415  NSAppleEventDescriptor *desc = nil;
416  switch (type[0]) {
417    // COV_NF_START
418    // I can't seem to convince objcType to return something of this type
419    case 'B':
420      desc = [NSAppleEventDescriptor descriptorWithBoolean:[self boolValue]];
421      break;
422    // COV_NF_END
423     
424    case 'c':
425    case 'C':
426    case 's':
427    case 'S':
428      desiredType = typeSInt16;
429      break;
430      
431    case 'i':
432    case 'l':
433      desiredType = typeSInt32;
434      break;
435    
436    // COV_NF_START
437    // I can't seem to convince objcType to return something of this type
438    case 'I':
439    case 'L':
440      desiredType = typeUInt32;
441      break;
442    // COV_NF_END
443      
444    case 'q':
445    case 'Q':
446      desiredType = typeSInt64;
447      break;
448      
449    case 'f':
450      desiredType = typeIEEE32BitFloatingPoint;
451      break;
452      
453    case 'd':
454    default:
455      desiredType = typeIEEE64BitFloatingPoint;
456      break;
457  }
458  
459  if (!desc) {
460    desc = [NSAppleEventDescriptor gtm_descriptorWithDouble:[self doubleValue]];
461    if (desc && desiredType != typeIEEE64BitFloatingPoint) {
462        desc = [desc coerceToDescriptorType:desiredType];
463    }
464  }
465  return desc;  
466}
467
468@end
469
470@implementation NSProcessInfo (GTMAppleEventDescriptorObjectAdditions)
471
472- (NSAppleEventDescriptor*)gtm_appleEventDescriptor {
473  ProcessSerialNumber psn = { 0, kCurrentProcess };
474  return [NSAppleEventDescriptor descriptorWithDescriptorType:typeProcessSerialNumber
475                                                        bytes:&psn
476                                                       length:sizeof(ProcessSerialNumber)];
477}  
478
479@end
480
481@implementation GTMFourCharCode (GTMAppleEventDescriptorObjectAdditions)
482
483+ (void)load {
484  DescType types[] = {
485    typeType, 
486    typeKeyword, 
487    typeApplSignature, 
488    typeEnumerated,
489  };
490  
491  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
492  [NSAppleEventDescriptor gtm_registerSelector:@selector(gtm_fourCharCodeValue)
493                                      forTypes:types
494                                         count:sizeof(types)/sizeof(DescType)];
495  [pool drain];
496}
497
498- (NSAppleEventDescriptor*)gtm_appleEventDescriptor {
499  return [self gtm_appleEventDescriptorOfType:typeType];
500}
501
502- (NSAppleEventDescriptor*)gtm_appleEventDescriptorOfType:(DescType)type {
503  FourCharCode code = [self fourCharCode];
504  return [NSAppleEventDescriptor descriptorWithDescriptorType:type 
505                                                        bytes:&code 
506                                                       length:sizeof(code)];
507}
508@end
509
510@implementation NSAppleEventDescriptor (GTMAppleEventDescriptorAdditions)
511
512- (BOOL)gtm_sendEventWithMode:(AESendMode)mode 
513                      timeOut:(NSTimeInterval)timeout
514                        reply:(NSAppleEventDescriptor**)reply {
515  BOOL isGood = YES;
516  AppleEvent replyEvent = { typeNull, NULL };
517  OSStatus err = AESendMessage([self aeDesc], &replyEvent, mode, timeout * 60);
518  NSAppleEventDescriptor *replyDesc 
519    = [[[NSAppleEventDescriptor alloc] initWithAEDescNoCopy:&replyEvent] autorelease];
520  if (err) {
521    isGood = NO;
522    _GTMDevLog(@"Unable to send message: %@ %d", self, (int)err);
523  } 
524  if (isGood) {
525    NSAppleEventDescriptor *errorDesc = [replyDesc descriptorForKeyword:keyErrorNumber];
526    if (errorDesc && [errorDesc int32Value]) {
527      isGood = NO;
528    }
529  }
530  if (reply) {
531    *reply = replyDesc;
532  }
533  return isGood;
534}
535
536@end