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