Add a new File Access preferences pane.
[macgdbp.git] / Source / Breakpoint.m
1 /*
2 * MacGDBp
3 * Copyright (c) 2007 - 2011, Blue Static <http://www.bluestatic.org>
4 *
5 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
6 * General Public License as published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
10 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along with this program; if not,
14 * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17 #import "Breakpoint.h"
18
19 #import "PreferenceNames.h"
20
21 NSString* const kBreakpointTypeFile = @"line";
22 NSString* const kBreakpointTypeFunctionEntry = @"call";
23
24 @implementation Breakpoint {
25 NSString* __weak _type;
26 unsigned long _debuggerId;
27
28 NSString* _file;
29 NSData* _secureBookmark;
30 NSURL* _secureFileAccess;
31
32 NSString* _functionName;
33 }
34
35 + (instancetype)breakpointAtLine:(unsigned long)line inFile:(NSString*)file
36 {
37 Breakpoint* breakpoint = [[Breakpoint alloc] init];
38 breakpoint->_type = kBreakpointTypeFile;
39 breakpoint->_file = [file copy];
40 breakpoint->_line = line;
41 return breakpoint;
42 }
43
44 + (instancetype)breakpointOnFunctionNamed:(NSString*)name
45 {
46 Breakpoint* breakpoint = [[Breakpoint alloc] init];
47 breakpoint->_type = kBreakpointTypeFunctionEntry;
48 breakpoint->_functionName = [name copy];
49 return breakpoint;
50 }
51
52 - (instancetype)initWithDictionary:(NSDictionary*)dict
53 {
54 if ((self = [super init])) {
55 NSString* type = [dict valueForKey:@"type"];
56 if (!type || [type isEqualToString:kBreakpointTypeFile]) {
57 _type = kBreakpointTypeFile;
58 _file = [[dict valueForKey:@"file"] copy];
59 _line = [[dict valueForKey:@"line"] intValue];
60 _secureBookmark = [[dict valueForKey:@"secureBookmark"] copy];
61 } else if ([type isEqualToString:kBreakpointTypeFunctionEntry]) {
62 _type = kBreakpointTypeFunctionEntry;
63 _functionName = [[dict valueForKey:@"function"] copy];
64 } else {
65 [NSException raise:NSInvalidArgumentException
66 format:@"Unknown Breakpoint type: %@", type];
67 }
68 }
69 return self;
70 }
71
72 - (void)dealloc {
73 if (_secureFileAccess)
74 [self stopSecureFileAccess];
75 }
76
77 /**
78 * Returns the string to display in the breakpoints list.
79 */
80 - (NSString*)displayValue
81 {
82 if (self.type == kBreakpointTypeFile) {
83 return [NSString stringWithFormat:@"%@:%ld", self.file, self.line];
84 } else if (self.type == kBreakpointTypeFunctionEntry) {
85 return [NSString stringWithFormat:@"%@()", self.functionName];
86 }
87 return nil;
88 }
89
90 /**
91 * Returns the transformed path for the breakpoint, as Xdebug needs it
92 */
93 - (NSString*)transformedPath
94 {
95 NSString* path = self.file;
96
97 NSMutableArray* transforms = [[NSUserDefaults standardUserDefaults] mutableArrayValueForKey:kPrefPathReplacements];
98 if (!transforms || [transforms count] < 1)
99 return path;
100
101 for (NSDictionary* replacement in transforms)
102 {
103 path = [path
104 stringByReplacingOccurrencesOfString:[replacement valueForKey:@"local"]
105 withString:[replacement valueForKey:@"remote"]
106 ];
107 }
108
109 return path;
110 }
111
112 - (BOOL)isEqual:(id)obj
113 {
114 if (![obj isKindOfClass:[self class]]) {
115 return NO;
116 }
117
118 Breakpoint* other = obj;
119 if (self.type != other.type) {
120 return NO;
121 }
122
123 if (self.type == kBreakpointTypeFile) {
124 return [self.file isEqualToString:other.file] && self.line == other.line;
125 } else if (self.type == kBreakpointTypeFunctionEntry) {
126 return [self.functionName isEqualToString:other.functionName];
127 }
128
129 return NO;
130 }
131
132 - (NSDictionary*)dictionary
133 {
134 if (self.type == kBreakpointTypeFile) {
135 NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithDictionary:@{
136 @"type" : self.type,
137 @"file" : self.file,
138 @"line" : @(self.line),
139 }];
140 if (self.secureBookmark)
141 [dict setObject:self.secureBookmark forKey:@"secureBookmark"];
142 return dict;
143 } else if (self.type == kBreakpointTypeFunctionEntry) {
144 return @{
145 @"type" : self.type,
146 @"function" : self.functionName
147 };
148 }
149 return nil;
150 }
151
152 - (BOOL)createSecureBookmark
153 {
154 NSURL* fileURL = [NSURL fileURLWithPath:self.file];
155 return [self _createSecureBookmarkWithURL:fileURL];
156 }
157
158 - (BOOL)_createSecureBookmarkWithURL:(NSURL*)url
159 {
160 NSError* error;
161 NSData* secureBookmark = [url bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope | NSURLBookmarkCreationSecurityScopeAllowOnlyReadAccess
162 includingResourceValuesForKeys:nil
163 relativeToURL:nil
164 error:&error];
165 if (secureBookmark) {
166 self.secureBookmark = secureBookmark;
167 return YES;
168 } else {
169 NSLog(@"Failed to create secure bookmark: %@", error);
170 return NO;
171 }
172 }
173
174 - (BOOL)startSecureFileAccess
175 {
176 assert(self.type == kBreakpointTypeFile);
177 if (_secureFileAccess)
178 return YES;
179 if (!_secureBookmark)
180 return NO;
181
182 BOOL isStale;
183 NSError* error;
184 _secureFileAccess = [NSURL URLByResolvingBookmarkData:_secureBookmark
185 options:NSURLBookmarkResolutionWithSecurityScope
186 relativeToURL:nil
187 bookmarkDataIsStale:&isStale
188 error:&error];
189 if (error) {
190 NSLog(@"Failed to access file via secure bookmark: %@", error);
191 return NO;
192 }
193 if (isStale)
194 [self _createSecureBookmarkWithURL:_secureFileAccess];
195
196 return [_secureFileAccess startAccessingSecurityScopedResource];
197 }
198
199 - (BOOL)stopSecureFileAccess
200 {
201 assert(self.type == kBreakpointTypeFile);
202 if (!_secureFileAccess)
203 return YES;
204 if (!_secureBookmark)
205 return NO;
206
207 [_secureFileAccess stopAccessingSecurityScopedResource];
208 _secureFileAccess = nil;
209 return YES;
210 }
211
212 - (NSString*)description
213 {
214 return [NSString stringWithFormat:@"Breakpoint %@", [[self dictionary] description]];
215 }
216
217 @end