1/*
2 * Copyright (C) 2009 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#import "config.h"
27#import "QuickLook.h"
28
29#if USE(QUICK_LOOK)
30
31#import "DocumentLoader.h"
32#import "FileSystemIOS.h"
33#import "Logging.h"
34#import "ResourceError.h"
35#import "ResourceHandle.h"
36#import "ResourceLoader.h"
37#import "RuntimeApplicationChecksIOS.h"
38#import "SoftLinking.h"
39#import "SynchronousResourceHandleCFURLConnectionDelegate.h"
40#import "WebCoreURLResponseIOS.h"
41#import <Foundation/Foundation.h>
42#import <Foundation/NSFileManager_NSURLExtras.h>
43#import <QuickLook/QLPreviewConverter.h>
44#import <QuickLook/QuickLookPrivate.h>
45#import <wtf/NeverDestroyed.h>
46#import <wtf/StdLibExtras.h>
47#import <wtf/Threading.h>
48#import <wtf/Vector.h>
49#import <wtf/text/WTFString.h>
50
51#if USE(CFNETWORK)
52#import <CFNetwork/CFURLConnection.h>
53
54@interface NSURLResponse (QuickLookDetails)
55+(NSURLResponse *)_responseWithCFURLResponse:(CFURLResponseRef)response;
56-(CFURLResponseRef)_CFURLResponse;
57@end
58#endif
59
60SOFT_LINK_FRAMEWORK_OPTIONAL(QuickLook)
61SOFT_LINK_CLASS(QuickLook, QLPreviewConverter)
62SOFT_LINK_MAY_FAIL(QuickLook, QLPreviewGetSupportedMIMETypes, NSSet *, (), ())
63SOFT_LINK_MAY_FAIL(QuickLook, QLTypeCopyBestMimeTypeForFileNameAndMimeType, NSString *, (NSString *fileName, NSString *mimeType), (fileName, mimeType))
64SOFT_LINK_MAY_FAIL(QuickLook, QLTypeCopyBestMimeTypeForURLAndMimeType, NSString *, (NSURL *url, NSString *mimeType), (url, mimeType))
65SOFT_LINK_MAY_FAIL(QuickLook, QLTypeCopyUTIForURLAndMimeType, NSString *, (NSURL *url, NSString *mimeType), (url, mimeType))
66SOFT_LINK_CONSTANT_MAY_FAIL(QuickLook, QLPreviewScheme, NSString *)
67
68namespace WebCore {
69    NSString *QLTypeCopyUTIForURLAndMimeType(NSURL *url, NSString *mimeType);
70}
71
72using namespace WebCore;
73
74Class WebCore::QLPreviewConverterClass()
75{
76#define QLPreviewConverter getQLPreviewConverterClass()
77    return QLPreviewConverter;
78#undef QLPreviewConverter
79}
80
81NSString *WebCore::QLTypeCopyBestMimeTypeForFileNameAndMimeType(NSString *fileName, NSString *mimeType)
82{
83    if (!canLoadQLTypeCopyBestMimeTypeForFileNameAndMimeType())
84        return nil;
85
86    return ::QLTypeCopyBestMimeTypeForFileNameAndMimeType(fileName, mimeType);
87}
88
89NSString *WebCore::QLTypeCopyBestMimeTypeForURLAndMimeType(NSURL *url, NSString *mimeType)
90{
91    if (!canLoadQLTypeCopyBestMimeTypeForURLAndMimeType())
92        return nil;
93
94    return ::QLTypeCopyBestMimeTypeForURLAndMimeType(url, mimeType);
95}
96
97NSSet *WebCore::QLPreviewGetSupportedMIMETypesSet()
98{
99    if (!canLoadQLPreviewGetSupportedMIMETypes())
100        return nil;
101
102    static NSSet *set = adoptNS(::QLPreviewGetSupportedMIMETypes()).leakRef();
103    return set;
104}
105
106NSString *WebCore::QLTypeCopyUTIForURLAndMimeType(NSURL *url, NSString *mimeType)
107{
108    if (!canLoadQLTypeCopyUTIForURLAndMimeType())
109        return nil;
110
111    return ::QLTypeCopyUTIForURLAndMimeType(url, mimeType);
112}
113
114NSDictionary *WebCore::QLFileAttributes()
115{
116    // Set file perms to owner read/write only
117    NSNumber *filePOSIXPermissions = [NSNumber numberWithInteger:(WEB_UREAD | WEB_UWRITE)];
118    static NSDictionary *dictionary = adoptNS([[NSDictionary alloc] initWithObjectsAndKeys:
119                                        NSUserName(), NSFileOwnerAccountName,
120                                        filePOSIXPermissions, NSFilePosixPermissions,
121                                        nullptr]).leakRef();
122    return dictionary;
123}
124
125NSDictionary *WebCore::QLDirectoryAttributes()
126{
127    // Set file perms to owner read/write/execute only
128    NSNumber *directoryPOSIXPermissions = [NSNumber numberWithInteger:(WEB_UREAD | WEB_UWRITE | WEB_UEXEC)];
129    static NSDictionary *dictionary = adoptNS([[NSDictionary alloc] initWithObjectsAndKeys:
130                                                NSUserName(), NSFileOwnerAccountName,
131                                                directoryPOSIXPermissions, NSFilePosixPermissions,
132                                                nullptr]).leakRef();
133    return dictionary;
134}
135
136static Mutex& qlPreviewConverterDictionaryMutex()
137{
138    static NeverDestroyed<Mutex> mutex;
139    return mutex;
140}
141
142static NSMutableDictionary *QLPreviewConverterDictionary()
143{
144    static NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
145    return dictionary;
146}
147
148static NSMutableDictionary *QLContentDictionary()
149{
150    static NSMutableDictionary *contentDictionary = [[NSMutableDictionary alloc] init];
151    return contentDictionary;
152}
153
154void WebCore::addQLPreviewConverterWithFileForURL(NSURL *url, id converter, NSString *fileName)
155{
156    ASSERT(url);
157    ASSERT(converter);
158    MutexLocker lock(qlPreviewConverterDictionaryMutex());
159    [QLPreviewConverterDictionary() setObject:converter forKey:url];
160    [QLContentDictionary() setObject:(fileName ? fileName : @"") forKey:url];
161}
162
163NSString *WebCore::qlPreviewConverterFileNameForURL(NSURL *url)
164{
165    return [QLContentDictionary() objectForKey:url];
166}
167
168NSString *WebCore::qlPreviewConverterUTIForURL(NSURL *url)
169{
170    id converter = nil;
171    {
172        MutexLocker lock(qlPreviewConverterDictionaryMutex());
173        converter = [QLPreviewConverterDictionary() objectForKey:url];
174    }
175    if (!converter)
176        return nil;
177    return [converter previewUTI];
178}
179
180void WebCore::removeQLPreviewConverterForURL(NSURL *url)
181{
182    MutexLocker lock(qlPreviewConverterDictionaryMutex());
183    [QLPreviewConverterDictionary() removeObjectForKey:url];
184
185    // Delete the file when we remove the preview converter
186    NSString *filename = qlPreviewConverterFileNameForURL(url);
187    if ([filename length])
188        [[NSFileManager defaultManager] _web_removeFileOnlyAtPath:filename];
189    [QLContentDictionary() removeObjectForKey:url];
190}
191
192PassOwnPtr<ResourceRequest> WebCore::registerQLPreviewConverterIfNeeded(NSURL *url, NSString *mimeType, NSData *data)
193{
194    RetainPtr<NSString> updatedMIMEType = adoptNS(WebCore::QLTypeCopyBestMimeTypeForURLAndMimeType(url, mimeType));
195
196    if ([WebCore::QLPreviewGetSupportedMIMETypesSet() containsObject:updatedMIMEType.get()]) {
197        RetainPtr<NSString> uti = adoptNS(WebCore::QLTypeCopyUTIForURLAndMimeType(url, updatedMIMEType.get()));
198
199        RetainPtr<id> converter = adoptNS([[QLPreviewConverterClass() alloc] initWithData:data name:nil uti:uti.get() options:nil]);
200        NSURLRequest *request = [converter previewRequest];
201
202        // We use [request URL] here instead of url since it will be
203        // the URL that the WebDataSource will see during -dealloc.
204        addQLPreviewConverterWithFileForURL([request URL], converter.get(), nil);
205
206        return adoptPtr(new ResourceRequest(request));
207    }
208
209    return nullptr;
210}
211
212const URL WebCore::safeQLURLForDocumentURLAndResourceURL(const URL& documentURL, const String& resourceURL)
213{
214    id converter = nil;
215    NSURL *nsDocumentURL = documentURL;
216    {
217        MutexLocker lock(qlPreviewConverterDictionaryMutex());
218        converter = [QLPreviewConverterDictionary() objectForKey:nsDocumentURL];
219    }
220
221    if (!converter)
222        return URL(ParsedURLString, resourceURL);
223
224    RetainPtr<NSURLRequest> request = adoptNS([[NSURLRequest alloc] initWithURL:[NSURL URLWithString:resourceURL]]);
225    NSURLRequest *safeRequest = [converter safeRequestForRequest:request.get()];
226    return [safeRequest URL];
227}
228
229static Vector<char> createQLPreviewProtocol()
230{
231    Vector<char> previewProtocol;
232#define QLPreviewScheme getQLPreviewScheme()
233    const char* qlPreviewScheme = [QLPreviewScheme UTF8String];
234#undef QLPreviewScheme
235    previewProtocol.append(qlPreviewScheme, strlen(qlPreviewScheme) + 1);
236    return previewProtocol;
237}
238
239const char* WebCore::QLPreviewProtocol()
240{
241    if (!canLoadQLPreviewScheme())
242        return "";
243
244    static NeverDestroyed<Vector<char>> previewProtocol(createQLPreviewProtocol());
245    return previewProtocol.get().data();
246}
247
248#if USE(CFNETWORK)
249// The way QuickLook works is we pass it an NSURLConnectionDelegate callback object at creation
250// time. Then we pass it all the data as we receive it. Once we've downloaded the full URL,
251// QuickLook turns around and send us, through this delegate, the HTML version of the file which we
252// pass on to WebCore. The flag m_finishedLoadingDataIntoConverter in QuickLookHandle decides
253// whether to pass the data to QuickLook or WebCore.
254//
255// This works fine when using NS APIs, but when using CFNetwork, we don't have a NSURLConnectionDelegate.
256// So we create WebQuickLookHandleAsDelegate as an intermediate delegate object and pass it to
257// QLPreviewConverter. The proxy delegate then forwards the messages on to the CFNetwork code.
258@interface WebQuickLookHandleAsDelegate : NSObject <NSURLConnectionDelegate> {
259    RefPtr<SynchronousResourceHandleCFURLConnectionDelegate> m_connectionDelegate;
260}
261
262- (id)initWithConnectionDelegate:(SynchronousResourceHandleCFURLConnectionDelegate*)connectionDelegate;
263- (void)clearHandle;
264@end
265
266@implementation WebQuickLookHandleAsDelegate
267- (id)initWithConnectionDelegate:(SynchronousResourceHandleCFURLConnectionDelegate*)connectionDelegate
268{
269    self = [super init];
270    if (!self)
271        return nil;
272    m_connectionDelegate = connectionDelegate;
273    return self;
274}
275
276- (void)connection:(NSURLConnection *)connection didReceiveDataArray:(NSArray *)dataArray
277{
278    UNUSED_PARAM(connection);
279    if (!m_connectionDelegate)
280        return;
281    LOG(Network, "WebQuickLookHandleAsDelegate::didReceiveDataArray()");
282    m_connectionDelegate->didReceiveDataArray(reinterpret_cast<CFArrayRef>(dataArray));
283}
284
285- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived
286{
287    UNUSED_PARAM(connection);
288    if (!m_connectionDelegate)
289        return;
290    LOG(Network, "WebQuickLookHandleAsDelegate::didReceiveData() - data length = %ld", (long)[data length]);
291
292    // QuickLook code sends us a nil data at times. The check below is the same as the one in
293    // ResourceHandleMac.cpp added for a different bug.
294    if (![data length])
295        return;
296    m_connectionDelegate->didReceiveData(reinterpret_cast<CFDataRef>(data), static_cast<int>(lengthReceived));
297}
298
299- (void)connectionDidFinishLoading:(NSURLConnection *)connection
300{
301    UNUSED_PARAM(connection);
302    if (!m_connectionDelegate)
303        return;
304    LOG(Network, "WebQuickLookHandleAsDelegate::didFinishLoading()");
305    m_connectionDelegate->didFinishLoading();
306}
307
308- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
309{
310    UNUSED_PARAM(connection);
311    if (!m_connectionDelegate)
312        return;
313    LOG(Network, "WebQuickLookHandleAsDelegate::didFail()");
314    m_connectionDelegate->didFail(reinterpret_cast<CFErrorRef>(error));
315}
316
317- (void)clearHandle
318{
319    m_connectionDelegate = nullptr;
320}
321@end
322#endif
323
324@interface WebResourceLoaderQuickLookDelegate : NSObject <NSURLConnectionDelegate> {
325    RefPtr<ResourceLoader> _resourceLoader;
326    BOOL _hasSentDidReceiveResponse;
327    BOOL _hasFailed;
328}
329@property (nonatomic) QuickLookHandle* quickLookHandle;
330@end
331
332@implementation WebResourceLoaderQuickLookDelegate
333
334- (id)initWithResourceLoader:(PassRefPtr<ResourceLoader>)resourceLoader
335{
336    self = [super init];
337    if (!self)
338        return nil;
339
340    _resourceLoader = resourceLoader;
341    return self;
342}
343
344- (void)_sendDidReceiveResponseIfNecessary
345{
346    if (_hasSentDidReceiveResponse || _hasFailed || !_quickLookHandle)
347        return;
348
349    // QuickLook might fail to convert a document without calling connection:didFailWithError: (see <rdar://problem/17927972>).
350    // A nil MIME type is an indication of such a failure, so stop loading the resource and ignore subsequent delegate messages.
351    NSURLResponse *previewResponse = _quickLookHandle->nsResponse();
352    if (![previewResponse MIMEType]) {
353        _hasFailed = YES;
354        _resourceLoader->didFail(_resourceLoader->cannotShowURLError());
355        return;
356    }
357
358    _hasSentDidReceiveResponse = YES;
359    _resourceLoader->didReceiveResponse(previewResponse);
360}
361
362#if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
363- (void)connection:(NSURLConnection *)connection didReceiveDataArray:(NSArray *)dataArray
364{
365    UNUSED_PARAM(connection);
366    if (!_resourceLoader)
367        return;
368
369    [self _sendDidReceiveResponseIfNecessary];
370    if (_hasFailed)
371        return;
372
373    _resourceLoader->didReceiveDataArray(reinterpret_cast<CFArrayRef>(dataArray));
374}
375#endif
376
377- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived
378{
379    UNUSED_PARAM(connection);
380    if (!_resourceLoader)
381        return;
382
383    [self _sendDidReceiveResponseIfNecessary];
384    if (_hasFailed)
385        return;
386
387    // QuickLook code sends us a nil data at times. The check below is the same as the one in
388    // ResourceHandleMac.cpp added for a different bug.
389    if (![data length])
390        return;
391    _resourceLoader->didReceiveData(reinterpret_cast<const char*>([data bytes]), [data length], lengthReceived, DataPayloadBytes);
392}
393
394- (void)connectionDidFinishLoading:(NSURLConnection *)connection
395{
396    UNUSED_PARAM(connection);
397    if (!_resourceLoader || _hasFailed)
398        return;
399
400    ASSERT(_hasSentDidReceiveResponse);
401    _resourceLoader->didFinishLoading(0);
402}
403
404- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
405{
406    UNUSED_PARAM(connection);
407
408    [self _sendDidReceiveResponseIfNecessary];
409    if (_hasFailed)
410        return;
411
412    _resourceLoader->didFail(ResourceError(error));
413}
414
415- (void)clearHandle
416{
417    _resourceLoader = nullptr;
418    _quickLookHandle = nullptr;
419}
420
421@end
422
423namespace WebCore {
424
425NSString *createTemporaryFileForQuickLook(NSString *fileName)
426{
427    NSString *downloadDirectory = createTemporaryDirectory(@"QuickLookContent");
428    if (!downloadDirectory)
429        return nil;
430
431    NSString *contentPath = [downloadDirectory stringByAppendingPathComponent:fileName];
432    NSFileManager *fileManager = [NSFileManager defaultManager];
433    NSString *uniqueContentPath = [fileManager _web_pathWithUniqueFilenameForPath:contentPath];
434
435    BOOL success = [fileManager _web_createFileAtPathWithIntermediateDirectories:uniqueContentPath
436                                                                        contents:nil
437                                                                      attributes:QLFileAttributes()
438                                                             directoryAttributes:QLDirectoryAttributes()];
439
440    return success ? uniqueContentPath : nil;
441}
442
443static inline QuickLookHandleClient* emptyClient()
444{
445    static NeverDestroyed<QuickLookHandleClient> emptyClient;
446    return &emptyClient.get();
447}
448
449QuickLookHandle::QuickLookHandle(NSURL *firstRequestURL, NSURLConnection *connection, NSURLResponse *nsResponse, id delegate)
450    : m_firstRequestURL(firstRequestURL)
451    , m_converter(adoptNS([[QLPreviewConverterClass() alloc] initWithConnection:connection delegate:delegate response:nsResponse options:nil]))
452    , m_delegate(delegate)
453    , m_finishedLoadingDataIntoConverter(false)
454    , m_nsResponse([m_converter previewResponse])
455    , m_client(emptyClient())
456{
457    LOG(Network, "QuickLookHandle::QuickLookHandle() - previewFileName: %s", [m_converter previewFileName]);
458}
459
460std::unique_ptr<QuickLookHandle> QuickLookHandle::create(ResourceHandle* handle, NSURLConnection *connection, NSURLResponse *nsResponse, id delegate)
461{
462    ASSERT_ARG(handle, handle);
463    if (!handle->firstRequest().deprecatedIsMainResourceRequest() || ![WebCore::QLPreviewGetSupportedMIMETypesSet() containsObject:[nsResponse MIMEType]])
464        return nullptr;
465
466    std::unique_ptr<QuickLookHandle> quickLookHandle(new QuickLookHandle([handle->firstRequest().nsURLRequest(DoNotUpdateHTTPBody) URL], connection, nsResponse, delegate));
467    handle->client()->didCreateQuickLookHandle(*quickLookHandle);
468    return WTF::move(quickLookHandle);
469}
470
471#if USE(CFNETWORK)
472std::unique_ptr<QuickLookHandle> QuickLookHandle::create(ResourceHandle* handle, SynchronousResourceHandleCFURLConnectionDelegate* connectionDelegate, CFURLResponseRef cfResponse)
473{
474    ASSERT_ARG(handle, handle);
475    if (!handle->firstRequest().deprecatedIsMainResourceRequest() || ![WebCore::QLPreviewGetSupportedMIMETypesSet() containsObject:(NSString *)CFURLResponseGetMIMEType(cfResponse)])
476        return nullptr;
477
478    NSURLResponse *nsResponse = [NSURLResponse _responseWithCFURLResponse:cfResponse];
479    WebQuickLookHandleAsDelegate *delegate = [[[WebQuickLookHandleAsDelegate alloc] initWithConnectionDelegate:connectionDelegate] autorelease];
480    std::unique_ptr<QuickLookHandle> quickLookHandle(new QuickLookHandle([handle->firstRequest().nsURLRequest(DoNotUpdateHTTPBody) URL], nil, nsResponse, delegate));
481    handle->client()->didCreateQuickLookHandle(*quickLookHandle);
482    return WTF::move(quickLookHandle);
483}
484
485CFURLResponseRef QuickLookHandle::cfResponse()
486{
487    return [m_nsResponse _CFURLResponse];
488}
489#endif
490
491static inline bool isMainResourceLoader(ResourceLoader* loader)
492{
493    return loader->documentLoader()->mainResourceLoader() == loader;
494}
495
496std::unique_ptr<QuickLookHandle> QuickLookHandle::create(ResourceLoader* loader, NSURLResponse *response)
497{
498    ASSERT_ARG(loader, loader);
499    if (!isMainResourceLoader(loader) || ![WebCore::QLPreviewGetSupportedMIMETypesSet() containsObject:[response MIMEType]])
500        return nullptr;
501
502    RetainPtr<WebResourceLoaderQuickLookDelegate> delegate = adoptNS([[WebResourceLoaderQuickLookDelegate alloc] initWithResourceLoader:loader]);
503    std::unique_ptr<QuickLookHandle> quickLookHandle(new QuickLookHandle([loader->originalRequest().nsURLRequest(DoNotUpdateHTTPBody) URL], nil, response, delegate.get()));
504    [delegate setQuickLookHandle:quickLookHandle.get()];
505    loader->didCreateQuickLookHandle(*quickLookHandle);
506    return WTF::move(quickLookHandle);
507}
508
509NSURLResponse *QuickLookHandle::nsResponse()
510{
511    return m_nsResponse.get();
512}
513
514bool QuickLookHandle::didReceiveDataArray(CFArrayRef cfDataArray)
515{
516    if (m_finishedLoadingDataIntoConverter)
517        return false;
518
519    LOG(Network, "QuickLookHandle::didReceiveDataArray()");
520    [m_converter appendDataArray:(NSArray *)cfDataArray];
521    m_client->didReceiveDataArray(cfDataArray);
522    return true;
523}
524
525bool QuickLookHandle::didReceiveData(CFDataRef cfData)
526{
527    if (m_finishedLoadingDataIntoConverter)
528        return false;
529
530    return didReceiveDataArray(adoptCF(CFArrayCreate(kCFAllocatorDefault, (const void**)&cfData, 1, &kCFTypeArrayCallBacks)).get());
531}
532
533bool QuickLookHandle::didFinishLoading()
534{
535    if (m_finishedLoadingDataIntoConverter)
536        return false;
537
538    LOG(Network, "QuickLookHandle::didFinishLoading()");
539    m_finishedLoadingDataIntoConverter = YES;
540    [m_converter finishedAppendingData];
541    m_client->didFinishLoading();
542    return true;
543}
544
545void QuickLookHandle::didFail()
546{
547    LOG(Network, "QuickLookHandle::didFail()");
548    m_client->didFail();
549    [m_converter finishConverting];
550    m_converter = nullptr;
551}
552
553QuickLookHandle::~QuickLookHandle()
554{
555    LOG(Network, "QuickLookHandle::~QuickLookHandle()");
556    m_converter = nullptr;
557
558    [m_delegate clearHandle];
559}
560
561String QuickLookHandle::previewFileName() const
562{
563    return [m_converter previewFileName];
564}
565
566String QuickLookHandle::previewUTI() const
567{
568    return [m_converter previewUTI];
569}
570
571NSURL *QuickLookHandle::previewRequestURL() const
572{
573    return [[m_converter previewRequest] URL];
574}
575
576}
577
578#endif // USE(QUICK_LOOK)
579