-
Notifications
You must be signed in to change notification settings - Fork 0
/
IDAlias.m
140 lines (112 loc) · 3.51 KB
/
IDAlias.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// IDAlias.m
// Force alias resolution in NSSavePanels under 10.8 for
// recalcitrant applications. Such as InDesign. Only load
// ourselves in apps on our list (InDesign and InCopy).
//
// John Hawkinson <[email protected]>
// 21 April 2013
//
// Derived from an example by Alexandre Colucci (timac.org)
#include <stdio.h>
#include <objc/Object.h>
#include <objc/runtime.h>
#include <Foundation/Foundation.h>
#include <AppKit/AppKit.h>
static IMP NSSavePanel_URLs = NULL;
@interface IDAlias:NSObject
{
}
@end
@implementation IDAlias
+(void)load
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSArray *appsToUse = [NSArray arrayWithObjects:
@"Adobe InDesign",
@"Adobe InCopy",
nil];
/* Of the methods discussed in
* Technical Q&A QA1544
* Obtaining the localized application name in Cocoa
* http://developer.apple.com/library/mac/#qa/qa1544/_index.html
*
* only methods (3) and (5) return useful strings for InDesign at this
* stage; the others return null:
*
* (lldb) po [[NSBundle mainBundle] bundlePath]
* /Applications/Adobe InDesign CC 2015/Adobe InDesign CC 2015.app
*
* (lldb) po [[NSProcessInfo processInfo] processName]
* Adobe InDesign CC 2015
*/
NSString *procName = [[NSProcessInfo processInfo] processName];
NSEnumerator *i = [appsToUse objectEnumerator];
id id;
BOOL found = NO;
while ((id = [i nextObject])) {
if ([procName rangeOfString:id].location == 0)
found = YES;
}
if (!found) {
#if DEBUG
NSLog(@"IDAlias in proc <%@> not ID/IC. Punting.", procName);
#endif
return;
}
NSLog(@"IDAlias interposing -[NSSavePanel URLs] in process <%@>.",
procName);
Class originalClass = NSClassFromString(@"NSSavePanel");
Method originalMeth = class_getInstanceMethod(originalClass,
@selector(URLs));
NSSavePanel_URLs = method_getImplementation(originalMeth);
Method replacementMeth = class_getInstanceMethod(
NSClassFromString(@"IDAlias"),
@selector(URLs));
method_exchangeImplementations(originalMeth, replacementMeth);
[pool drain];
}
-(NSArray*)URLs
{
int count;
NSError *error = nil;
NSArray *originalURLArray;
// We first call the original method
originalURLArray = NSSavePanel_URLs(self, @selector(URLs), self);
count = [originalURLArray count];
if (!count) { // skip out early
return originalURLArray;
}
// Run our custom code
NSMutableArray *urlArray = [originalURLArray mutableCopy];
int i;
for (i=0; i<count; i++) {
NSURL *url = [urlArray objectAtIndex:i];
#ifdef DEBUG
fprintf(stderr, "URL: %s\n",
[[url path] UTF8String]);
#endif
NSData *alias = [NSURL bookmarkDataWithContentsOfURL:url error:&error];
if (alias == NULL) {
// Not an alias! A-OK!
continue;
}
BOOL isStale;
// If we could depend on 10.10, we would use
// [NSURL URLByResolvingAliasFileAtURL] and skip the whole
// create bookmark/ resolve bookmark nonsense.
NSURL *realURL = [NSURL URLByResolvingBookmarkData:alias options:0
relativeToURL:nil
bookmarkDataIsStale:&isStale
error:&error];
if (isStale || realURL == NULL) {
// if (realURL == NULL) {
NSLog(@"IDAlias failed alias resolution: %@", error);
}
[urlArray replaceObjectAtIndex:i withObject:realURL];
#ifdef DEBUG
NSLog(@"IDAlias replaced path with realPath:%@", [realURL path]);
#endif
}
return urlArray;
}
@end