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