_WKAttachment.mm   [plain text]

/*
* Copyright (C) 2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/

#import "config.h"
#import "_WKAttachment.h"

#if WK_API_ENABLED

#import "APIAttachment.h"
#import "WKErrorPrivate.h"
#import "_WKAttachmentInternal.h"
#import <WebCore/MIMETypeRegistry.h>
#import <WebCore/SharedBuffer.h>
#import <wtf/BlockPtr.h>

#if PLATFORM(IOS_FAMILY)
#import <MobileCoreServices/MobileCoreServices.h>
#endif

static const NSInteger UnspecifiedAttachmentErrorCode = 1;
static const NSInteger InvalidAttachmentErrorCode = 2;

@implementation _WKAttachmentDisplayOptions : NSObject
@end

@implementation _WKAttachmentInfo {
RetainPtr<NSFileWrapper> _fileWrapper;
RetainPtr<NSString> _mimeType;
RetainPtr<NSString> _utiType;
RetainPtr<NSString> _filePath;
}

- (instancetype)initWithFileWrapper:(NSFileWrapper *)fileWrapper filePath:(NSString *)filePath mimeType:(NSString *)mimeType utiType:(NSString *)utiType
{
if (!(self = [super init]))
return nil;

_fileWrapper = fileWrapper;
_filePath = filePath;
_mimeType = mimeType;
_utiType = utiType;
return self;
}

- (NSData *)data
{
if (![_fileWrapper isRegularFile]) {
// FIXME: Handle attachments backed by NSFileWrappers that represent directories.
return nil;
}

return [_fileWrapper regularFileContents];
}

- (NSString *)name
{
if ([_fileWrapper filename].length)
return [_fileWrapper filename];

return [_fileWrapper preferredFilename];
}

- (NSString *)filePath
{
return _filePath.get();
}

- (NSFileWrapper *)fileWrapper
{
return _fileWrapper.get();
}

- (NSString *)contentType
{
if ([_mimeType length])
return _mimeType.get();

return _utiType.get();
}

@end

@implementation _WKAttachment

- (API::Object&)_apiObject
{
return *_attachment;
}

- (_WKAttachmentInfo *)info
{
if (!_attachment->isValid())
return nil;

return [[[_WKAttachmentInfo alloc] initWithFileWrapper:_attachment->fileWrapper() filePath:_attachment->filePath() mimeType:_attachment->mimeType() utiType:_attachment->utiType()] autorelease];
}

- (void)requestInfo:(void(^)(_WKAttachmentInfo *, NSError *))completionHandler
{
completionHandler(self.info, nil);
}

- (void)setFileWrapper:(NSFileWrapper *)fileWrapper contentType:(NSString *)contentType completion:(void (^)(NSError *))completionHandler
{
if (!_attachment->isValid()) {
completionHandler([NSError errorWithDomain:WKErrorDomain code:InvalidAttachmentErrorCode userInfo:nil]);
return;
}

// This file path member is only populated when the attachment is generated upon dropping files. When data is specified via NSFileWrapper
// from the SPI client, the corresponding file path of the data is unknown, if it even exists at all.
_attachment->setFilePath({ });
_attachment->setFileWrapperAndUpdateContentType(fileWrapper, contentType);
_attachment->updateAttributes([capturedBlock = makeBlockPtr(completionHandler)] (auto error) {
if (!capturedBlock)
return;

if (error == WebKit::CallbackBase::Error::None)
capturedBlock(nil);
else
capturedBlock([NSError errorWithDomain:WKErrorDomain code:UnspecifiedAttachmentErrorCode userInfo:nil]);
});
}

- (void)setData:(NSData *)data newContentType:(NSString *)newContentType newFilename:(NSString *)newFilename completion:(void(^)(NSError *))completionHandler
{
auto fileWrapper = adoptNS([[NSFileWrapper alloc] initRegularFileWithContents:data]);
if (newFilename)
[fileWrapper setPreferredFilename:newFilename];
[self setFileWrapper:fileWrapper.get() contentType:newContentType completion:completionHandler];
}

- (NSString *)uniqueIdentifier
{
return _attachment->identifier();
}

- (NSString *)description
{
return [NSString stringWithFormat:@"<%@ %p id='%@'>", [self class], self, self.uniqueIdentifier];
}

- (BOOL)isConnected
{
return _attachment->insertionState() == API::Attachment::InsertionState::Inserted;
}

@end

#endif // WK_API_ENABLED