PageRenderTime 169ms CodeModel.GetById 26ms RepoModel.GetById 2ms app.codeStats 0ms

/core/externals/google-toolbox-for-mac/SpotlightPlugins/InterfaceBuilder/GetMetadataForFile.m

http://macfuse.googlecode.com/
Objective C | 208 lines | 169 code | 15 blank | 24 comment | 31 complexity | f59b7958cd034add99cea5dc6ab1dd2e MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause, GPL-2.0
  1. //
  2. // GetMetadataForFile.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 <Foundation/Foundation.h>
  19. #import "GTMGarbageCollection.h"
  20. static BOOL AddStringsToTextContent(NSSet *stringSet,
  21. NSMutableDictionary *attributes) {
  22. BOOL wasGood = NO;
  23. if ([stringSet count]) {
  24. NSString *allStrings = [[stringSet allObjects] componentsJoinedByString:@"\n"];
  25. NSString *oldContent = [attributes objectForKey:(NSString*)kMDItemTextContent];
  26. if (oldContent) {
  27. allStrings = [NSString stringWithFormat:@"%@\n%@", allStrings, oldContent];
  28. }
  29. [attributes setObject:allStrings forKey:(NSString*)kMDItemTextContent];
  30. wasGood = YES;
  31. }
  32. return wasGood;
  33. }
  34. static BOOL ExtractClasses(NSDictionary *ibToolData,
  35. NSMutableDictionary *attributes) {
  36. NSString *classesKey = @"com.apple.ibtool.document.classes";
  37. NSDictionary *classes = [ibToolData objectForKey:classesKey];
  38. NSMutableSet *classSet = [NSMutableSet set];
  39. NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
  40. NSArray *classPrefixesToIgnore
  41. = [ud objectForKey:@"classPrefixesToIgnore"];
  42. if (!classPrefixesToIgnore) {
  43. classPrefixesToIgnore = [NSArray arrayWithObjects:
  44. @"IB",
  45. @"FirstResponder",
  46. @"NS",
  47. @"Web",
  48. nil];
  49. [ud setObject:classPrefixesToIgnore forKey:@"classPrefixesToIgnore"];
  50. [ud synchronize];
  51. }
  52. NSDictionary *entry;
  53. NSEnumerator *entryEnum = [classes objectEnumerator];
  54. while ((entry = [entryEnum nextObject])) {
  55. NSString *classStr = [entry objectForKey:@"class"];
  56. if (classStr) {
  57. NSString *prefix;
  58. NSEnumerator *classPrefixesToIgnoreEnum
  59. = [classPrefixesToIgnore objectEnumerator];
  60. while (classStr && (prefix = [classPrefixesToIgnoreEnum nextObject])) {
  61. if ([classStr hasPrefix:prefix]) {
  62. classStr = nil;
  63. }
  64. }
  65. if (classStr) {
  66. [classSet addObject:classStr];
  67. }
  68. }
  69. }
  70. return AddStringsToTextContent(classSet, attributes);
  71. }
  72. static BOOL ExtractLocalizableStrings(NSDictionary *ibToolData,
  73. NSMutableDictionary *attributes) {
  74. NSString *localStrKey = @"com.apple.ibtool.document.localizable-strings";
  75. NSDictionary *strings = [ibToolData objectForKey:localStrKey];
  76. NSMutableSet *stringSet = [NSMutableSet set];
  77. NSDictionary *entry;
  78. NSEnumerator *entryEnum = [strings objectEnumerator];
  79. while ((entry = [entryEnum nextObject])) {
  80. NSEnumerator *stringEnum = [entry objectEnumerator];
  81. NSString *string;
  82. while ((string = [stringEnum nextObject])) {
  83. [stringSet addObject:string];
  84. }
  85. }
  86. return AddStringsToTextContent(stringSet, attributes);
  87. }
  88. static BOOL ExtractConnections(NSDictionary *ibToolData,
  89. NSMutableDictionary *attributes) {
  90. NSString *connectionsKey = @"com.apple.ibtool.document.connections";
  91. NSDictionary *connections = [ibToolData objectForKey:connectionsKey];
  92. NSMutableSet *connectionsSet = [NSMutableSet set];
  93. NSDictionary *entry;
  94. NSEnumerator *entryEnum = [connections objectEnumerator];
  95. while ((entry = [entryEnum nextObject])) {
  96. NSString *typeStr = [entry objectForKey:@"type"];
  97. NSString *value = nil;
  98. if (typeStr) {
  99. if ([typeStr isEqualToString:@"IBBindingConnection"]) {
  100. value = [entry objectForKey:@"keypath"];
  101. } else if ([typeStr isEqualToString:@"IBCocoaOutletConnection"] ||
  102. [typeStr isEqualToString:@"IBCocoaActionConnection"]) {
  103. value = [entry objectForKey:@"label"];
  104. }
  105. if (value) {
  106. [connectionsSet addObject:value];
  107. }
  108. }
  109. }
  110. return AddStringsToTextContent(connectionsSet, attributes);
  111. }
  112. static NSString *FindIBTool(void) {
  113. NSString *result = nil;
  114. NSString *possiblePaths[] = {
  115. @"/usr/bin/ibtool",
  116. @"/Developer/usr/bin/ibtool",
  117. };
  118. NSFileManager *fm = [NSFileManager defaultManager];
  119. BOOL isDir;
  120. for (size_t i = 0; i < (sizeof(possiblePaths) / sizeof(NSString*)); ++i) {
  121. if ([fm fileExistsAtPath:possiblePaths[i] isDirectory:&isDir] &&
  122. !isDir) {
  123. result = possiblePaths[i];
  124. break;
  125. }
  126. }
  127. return result;
  128. }
  129. static NSData *CommandOutput(NSString *cmd) {
  130. NSMutableData *result = [NSMutableData data];
  131. // NOTE: we use popen/pclose in here instead of NSTask because NSTask uses
  132. // a delayed selector to clean up the process it spawns, so since we have
  133. // no runloop it gets ungly trying to clean up the zombie process.
  134. FILE *fp;
  135. char buffer[2048];
  136. size_t len;
  137. if((fp = popen([cmd UTF8String], "r"))) {
  138. // spool it all in
  139. while ((len = fread(buffer, 1, sizeof(buffer), fp)) > 0) {
  140. [result appendBytes:buffer length:len];
  141. }
  142. // make sure we get a clean exit status
  143. if (pclose(fp) != 0) {
  144. result = nil;
  145. }
  146. }
  147. return result;
  148. }
  149. static BOOL ImportIBFile(NSMutableDictionary *attributes,
  150. NSString *pathToFile) {
  151. BOOL wasGood = NO;
  152. NSString *ibtoolPath = FindIBTool();
  153. if (ibtoolPath) {
  154. NSString *cmdString
  155. = @"%@ --classes --localizable-strings --connections \"%@\"";
  156. NSString *cmd = [NSString stringWithFormat:cmdString, ibtoolPath, pathToFile];
  157. NSData *data = CommandOutput(cmd);
  158. if (data) {
  159. NSDictionary *results
  160. = GTMCFAutorelease(CFPropertyListCreateFromXMLData(NULL,
  161. (CFDataRef)data ,
  162. kCFPropertyListImmutable,
  163. NULL));
  164. if (results && [results isKindOfClass:[NSDictionary class]]) {
  165. wasGood = ExtractClasses(results, attributes);
  166. wasGood |= ExtractLocalizableStrings(results, attributes);
  167. wasGood |= ExtractConnections(results, attributes);
  168. }
  169. }
  170. }
  171. return wasGood;
  172. }
  173. // Grabs all of the classes, localizable strings, bindings, outlets
  174. // and actions and sticks them into kMDItemTextContent.
  175. Boolean GetMetadataForFile(void* interface,
  176. CFMutableDictionaryRef cfAttributes,
  177. CFStringRef contentTypeUTI,
  178. CFStringRef cfPathToFile) {
  179. NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  180. NSMutableDictionary *attributes = (NSMutableDictionary*)cfAttributes;
  181. NSString *pathToFile = (NSString*)cfPathToFile;
  182. BOOL wasGood = NO;
  183. if (UTTypeConformsTo(contentTypeUTI,
  184. CFSTR("com.apple.interfacebuilder.document"))
  185. || UTTypeConformsTo(contentTypeUTI,
  186. CFSTR("com.apple.interfacebuilder.document.cocoa"))
  187. || UTTypeConformsTo(contentTypeUTI,
  188. CFSTR("com.apple.interfacebuilder.document.carbon"))) {
  189. wasGood = ImportIBFile(attributes, pathToFile);
  190. }
  191. [pool release];
  192. return wasGood == NO ? FALSE : TRUE;
  193. }