]> git.lyx.org Git - lyx.git/blob - src/support/linkback/LinkBackProxy.m
Account for old versions of Pygments
[lyx.git] / src / support / linkback / LinkBackProxy.m
1 /**
2  * \file LinkBackProxy.m
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Stefan Schimanski
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "support/linkback/LinkBackProxy.h"
14
15 #include "support/linkback/LinkBack.h"
16
17 ///////////////////////////////////////////////////////////////////////
18
19 @interface LyXLinkBackClient : NSObject <LinkBackClientDelegate> {
20         NSMutableSet * keys;
21 }
22
23 - (LyXLinkBackClient *)init;
24 - (BOOL)edit:(NSString *)fileName;
25 @end
26
27 @implementation LyXLinkBackClient
28
29 - (LyXLinkBackClient *)init
30 {
31         self = [super init];
32         if (self != nil)
33                 keys = [[NSMutableSet alloc] init];
34         return self;
35 }
36
37 - (void)dealloc {
38         // close all links
39         NSArray * allKeys = [keys allObjects];
40         unsigned i;
41         for (i = 0; i < [allKeys count]; ++i) {
42                 LinkBack * link
43                 = [LinkBack activeLinkBackForItemKey:[allKeys objectAtIndex:i]];
44                 [link closeLink];
45         }
46         [keys release];
47
48         [super dealloc];
49 }
50
51 - (BOOL)edit:(NSString *)fileName
52 {
53         if ([LinkBack activeLinkBackForItemKey:fileName])
54                 return YES;
55
56         @try {
57                 // get put data, i.e. PDF + LinkBack + 4 bytes PDF-length
58                 NSData * data = [NSData dataWithContentsOfFile:fileName];
59                 if (data == nil) {
60                         NSLog(@"Cannot read file %@", fileName);
61                         return NO;
62                 }
63                 
64                 // Get linkback data which comes behind the pdf data.
65                 // The pdf data length are the last 4 bytes.
66                 UInt32 pdfLen = 0;
67                 pdfLen = *(UInt32 const *)(((UInt8 const *)[data bytes]) + [data length] - 4);
68                 pdfLen = NSSwapBigLongToHost(pdfLen); // make it big endian
69                 if (pdfLen >= [data length] - 4) {
70                         NSLog(@"Invalid file %@ for LinkBack", fileName);
71                         return NO;
72                 }
73                         
74                 NSData * linkBackData 
75                 = [data subdataWithRange:NSMakeRange(pdfLen, [data length] - pdfLen - 4)]; 
76                 if (linkBackData == nil) {
77                         NSLog(@"Invalid file %@ for LinkBack", fileName);
78                         return NO;
79                 }
80                 
81                 NSMutableDictionary * linkBackDataDict
82                 = [NSUnarchiver unarchiveObjectWithData:linkBackData];
83                 if (linkBackDataDict == nil) {
84                         NSLog(@"LinkBack data in %@ corrupted", fileName);
85                         return NO;
86                 }
87                 
88                 // create the link to the LinkBack server
89                 LinkBack * link = [LinkBack editLinkBackData:linkBackDataDict
90                         sourceName:fileName delegate:self itemKey:fileName];
91                 if (link == nil) {
92                         NSLog(@"Failed to create LinkBack link for %@", fileName);
93                         return NO;
94                 }
95                 [keys addObject:fileName];
96         }
97         @catch (NSException * exception) {
98                 NSLog(@"LinkBack exception: %@", exception);
99                 return NO;
100         }
101         
102         return YES;
103 }
104
105 - (void)linkBackDidClose:(LinkBack*)link
106 {
107         NSString * fileName = [link itemKey];
108         if (fileName) {
109                 [keys removeObject:fileName];
110                 NSLog(@"LinkBack link for %@ closed", fileName);
111         }
112 }
113
114 - (void)linkBackServerDidSendEdit:(LinkBack*)link
115 {
116         @try {
117                 // get pasteboard and check that linkback and pdf data is available
118                 NSPasteboard * pboard = [link pasteboard];
119                 NSArray * linkBackType = [NSArray arrayWithObjects: LinkBackPboardType, nil];
120                 NSArray * pdfType = [NSArray arrayWithObjects: NSPDFPboardType, nil];
121                 if ([pboard availableTypeFromArray:linkBackType] == nil
122                     || [pboard availableTypeFromArray:pdfType] == nil) {
123                         NSLog(@"No PDF or LinkBack data in pasteboard");
124                         return;
125                 }
126                         
127                 // get new linkback data
128                 id linkBackDataDict = [pboard propertyListForType:LinkBackPboardType];
129                 if (linkBackDataDict == nil) {
130                         NSLog(@"Cannot get LinkBack data from pasteboard");
131                         return;
132                 }
133                 NSData * linkBackData = [NSArchiver archivedDataWithRootObject:linkBackDataDict];
134                 if (linkBackData == nil) {
135                         NSLog(@"Cannot archive LinkBack data");
136                         return;
137                 }
138                 
139                 // get pdf
140                 NSData * pdfData = [pboard dataForType:NSPDFPboardType];
141                 if (pdfData == nil) {
142                         NSLog(@"Cannot get PDF data from pasteboard");
143                         return;
144                 }
145                 
146                 // update the file
147                 NSString * fileName = [link itemKey];
148                 NSFileHandle * file = [NSFileHandle fileHandleForUpdatingAtPath:fileName];
149                 if (file == nil) {
150                         NSLog(@"LinkBack file %@ disappeared.", fileName);
151                         return;
152                 }
153                 [file truncateFileAtOffset:0];
154                 [file writeData:pdfData];
155                 [file writeData:linkBackData];
156                 
157                 UInt32 pdfLen = NSSwapHostLongToBig([pdfData length]); // big endian
158                 NSData * lenData = [NSData dataWithBytes:&pdfLen length:4];
159                 [file writeData:lenData];
160                 [file closeFile];
161         }
162         @catch (NSException * exception) {
163                 NSLog(@"LinkBack exception in linkBackServerDidSendEdit: %@", exception);
164         }
165 }
166
167 @end
168
169
170 ///////////////////////////////////////////////////////////////////////
171
172 static LyXLinkBackClient * linkBackClient = nil;
173
174 int isLinkBackDataInPasteboard()
175 {
176         NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
177         NSArray * linkBackType = [NSArray arrayWithObjects: LinkBackPboardType, nil];
178         NSString * ret = [[NSPasteboard generalPasteboard] availableTypeFromArray:linkBackType];
179         [pool release];
180         return ret != nil;
181 }
182
183
184 void getLinkBackData(void const * * buf, unsigned * len)
185 {
186         NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
187         // get linkback data from pasteboard
188         NSPasteboard * pboard = [NSPasteboard generalPasteboard];
189         id linkBackData = [pboard propertyListForType:LinkBackPboardType];
190                 
191         NSData * nsdata = [NSArchiver archivedDataWithRootObject:linkBackData];
192         if (nsdata == nil) {
193                 *buf = 0;
194                 *len = 0;
195         } else {
196                 *buf = [nsdata bytes];
197                 *len = [nsdata length];
198         }
199         [pool release];
200 }
201
202
203 int editLinkBackFile(char const * docName)
204 {
205         // setup Obj-C and our client
206         if (linkBackClient == nil)
207                 linkBackClient = [[LyXLinkBackClient alloc] init];
208         NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
209         // FIXME: really UTF8 here?
210         NSString * nsDocName = [NSString stringWithUTF8String:docName];
211         int result = [linkBackClient edit:nsDocName] == YES;
212         [pool release];
213         return result;
214 }
215
216
217 void closeAllLinkBackLinks()
218 {
219         if (linkBackClient != nil) {
220                 [linkBackClient release];
221                 linkBackClient = nil;
222         }
223 }
224