Convert DataSource to Objective-C.

// FREEBIE
This commit is contained in:
Matthew Chen 2017-09-08 11:41:40 -04:00
parent 2282733fa9
commit 69816cdf0e
9 changed files with 549 additions and 251 deletions

View file

@ -89,7 +89,6 @@
34D8C0271ED3673300188D7C /* DebugUIMessages.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D8C0241ED3673300188D7C /* DebugUIMessages.m */; };
34D8C0281ED3673300188D7C /* DebugUITableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D8C0261ED3673300188D7C /* DebugUITableViewController.m */; };
34D8C02B1ED3685800188D7C /* DebugUIContacts.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D8C02A1ED3685800188D7C /* DebugUIContacts.m */; };
34D9134A1F62D4A500722898 /* DataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D913481F62D4A500722898 /* DataSource.swift */; };
34D9134B1F62D4A500722898 /* SignalAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D913491F62D4A500722898 /* SignalAttachment.swift */; };
34D99C8C1F27B13B00D284D6 /* OWSViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D99C8B1F27B13B00D284D6 /* OWSViewController.m */; };
34D99C931F2937CC00D284D6 /* OWSAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D99C911F2937CC00D284D6 /* OWSAnalytics.swift */; };
@ -551,7 +550,6 @@
34D8C0261ED3673300188D7C /* DebugUITableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = DebugUITableViewController.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
34D8C0291ED3685800188D7C /* DebugUIContacts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUIContacts.h; sourceTree = "<group>"; };
34D8C02A1ED3685800188D7C /* DebugUIContacts.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugUIContacts.m; sourceTree = "<group>"; };
34D913481F62D4A500722898 /* DataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataSource.swift; sourceTree = "<group>"; };
34D913491F62D4A500722898 /* SignalAttachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalAttachment.swift; sourceTree = "<group>"; };
34D99C8A1F27B13B00D284D6 /* OWSViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSViewController.h; sourceTree = "<group>"; };
34D99C8B1F27B13B00D284D6 /* OWSViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSViewController.m; sourceTree = "<group>"; };
@ -1231,7 +1229,6 @@
children = (
45CD81EE1DC030E7004C9430 /* AccountManager.swift */,
45DF5DF11DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift */,
34D913481F62D4A500722898 /* DataSource.swift */,
45666EC41D99483D008FE134 /* OWSAvatarBuilder.h */,
45666EC51D99483D008FE134 /* OWSAvatarBuilder.m */,
45C681B51D305A580050903A /* OWSCall.h */,
@ -2325,7 +2322,6 @@
458E38371D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m in Sources */,
FCFA64B41A24F3880007FB87 /* UIColor+OWS.m in Sources */,
4517642B1DE939FD00EDB8B9 /* ContactCell.swift in Sources */,
34D9134A1F62D4A500722898 /* DataSource.swift in Sources */,
450573FE1E78A06D00615BB4 /* OWS103EnableVideoCalling.m in Sources */,
34B3F8751E8DF1700035BE1A /* CallViewController.swift in Sources */,
34D8C0281ED3673300188D7C /* DebugUITableViewController.m in Sources */,

View file

@ -365,7 +365,7 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
return NO;
}
DataSourceUrl *dataSource = [[DataSourceUrl alloc] init:url];
id<DataSource> _Nullable dataSource = [DataSourcePath dataSourceWithURL:url];
SignalAttachment *attachment =
[SignalAttachment attachmentWithDataSource:dataSource dataUTI:utiType filename:filename];
if (!attachment) {

View file

@ -1,217 +0,0 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
import Foundation
@objc
protocol DataSource {
// This method should not be called unless necessary as it
// be expensive.
func data() -> Data
func dataUrl(fileExtension: String) -> URL?
func dataPath(fileExtension: String) -> String?
func dataPathIfOnDisk() -> String?
func dataLength() -> Int
}
@objc
class DataSourceValue: NSObject, DataSource {
static let TAG = "[DataSourceValue]"
private let value: Data
private var path: String?
// MARK: Constructor
internal required init(_ value: Data) {
self.value = value
super.init()
}
func data() -> Data {
return value
}
func dataUrl(fileExtension: String) -> URL? {
guard let path = dataPath(fileExtension:fileExtension) else {
return nil
}
return URL(fileURLWithPath: path)
}
func dataPath(fileExtension: String) -> String? {
if let path = path {
return path
}
let directory = NSTemporaryDirectory()
let fileName = NSUUID().uuidString + "." + fileExtension
let filePath = (directory as NSString).appendingPathComponent(fileName)
do {
try value.write(to: URL(fileURLWithPath:filePath))
path = filePath
} catch {
owsFail("\(DataSourceValue.TAG) Could not write data to disk: \(fileExtension)")
}
return filePath
}
func dataPathIfOnDisk() -> String? {
if let path = path {
return path
}
return nil
}
func dataLength() -> Int {
return value.count
}
class func empty() -> DataSource {
return DataSourceValue(Data())
}
}
@objc
class DataSourcePath: NSObject, DataSource {
static let TAG = "[DataSourcePath]"
private let path: String
private var cachedData: Data?
private var cachedLength: Int?
// MARK: Constructor
internal required init(_ path: String) {
self.path = path
super.init()
}
func data() -> Data {
if let cachedData = cachedData {
return cachedData
}
Logger.error("\(DataSourcePath.TAG) reading data: \(path)")
do {
try cachedData = NSData(contentsOfFile:path) as Data
} catch {
owsFail("\(DataSourcePath.TAG) Could not read data from disk: \(path)")
cachedData = Data()
}
return cachedData!
}
func dataUrl(fileExtension: String) -> URL? {
return URL(fileURLWithPath: path)
}
func dataPath(fileExtension: String) -> String? {
return path
}
func dataPathIfOnDisk() -> String? {
return path
}
func dataLength() -> Int {
if let cachedLength = cachedLength {
return cachedLength
}
do {
let fileAttributes = try FileManager.default.attributesOfItem(atPath: path)
let fileSize = fileAttributes[FileAttributeKey.size] as! UInt64
cachedLength = Int(fileSize)
} catch {
owsFail("\(DataSourcePath.TAG) Could not read data length from disk: \(path)")
cachedLength = 0
}
return cachedLength!
}
}
@objc
class DataSourceUrl: NSObject, DataSource {
static let TAG = "[DataSourceUrl]"
private let url: URL
private var cachedData: Data?
private var cachedLength: Int?
// MARK: Constructor
internal required init(_ url: URL) {
if !url.isFileURL {
owsFail("\(DataSourceUrl.TAG) URL is not a file URL: \(url)")
}
self.url = url
super.init()
}
func data() -> Data {
if let cachedData = cachedData {
return cachedData
}
guard url.isFileURL else {
owsFail("\(DataSourceUrl.TAG) URL is not a file URL: \(url)")
return Data()
}
Logger.error("\(DataSourceUrl.TAG) reading data: \(url)")
do {
try cachedData = Data(contentsOf:url)
} catch {
owsFail("\(DataSourceUrl.TAG) Could not read data from disk: \(url)")
cachedData = Data()
}
return cachedData!
}
func dataUrl(fileExtension: String) -> URL? {
return url
}
func dataPath(fileExtension: String) -> String? {
guard url.isFileURL else {
owsFail("\(DataSourceUrl.TAG) URL is not a file URL: \(url)")
return nil
}
return url.path
}
func dataPathIfOnDisk() -> String? {
guard url.isFileURL else {
owsFail("\(DataSourceUrl.TAG) URL is not a file URL: \(url)")
return nil
}
return url.path
}
func dataLength() -> Int {
if let cachedLength = cachedLength {
return cachedLength
}
guard url.isFileURL else {
owsFail("\(DataSourceUrl.TAG) URL is not a file URL: \(url)")
return 0
}
do {
let fileAttributes = try FileManager.default.attributesOfItem(atPath: url.path)
let fileSize = fileAttributes[FileAttributeKey.size] as! UInt64
cachedLength = Int(fileSize)
} catch {
owsFail("\(DataSourceUrl.TAG) Could not read data length from disk: \(url)")
cachedLength = 0
}
return cachedLength!
}
}

View file

@ -66,11 +66,11 @@ class SignalAttachment: NSObject {
public var data: Data {
return dataSource.data()
}
public var dataLength: Int {
public var dataLength: UInt {
return dataSource.dataLength()
}
public var dataUrl: URL? {
return dataSource.dataUrl(fileExtension:fileExtensionNonNil)
return dataSource.dataUrl(fileExtensionNonNil)
}
// Attachment types are identified using UTIs.
@ -107,11 +107,11 @@ class SignalAttachment: NSObject {
*
* https://github.com/WhisperSystems/Signal-Android/blob/master/src/org/thoughtcrime/securesms/mms/PushMediaConstraints.java
*/
static let kMaxFileSizeAnimatedImage = 25 * 1024 * 1024
static let kMaxFileSizeImage = 6 * 1024 * 1024
static let kMaxFileSizeVideo = 100 * 1024 * 1024
static let kMaxFileSizeAudio = 100 * 1024 * 1024
static let kMaxFileSizeGeneric = 100 * 1024 * 1024
static let kMaxFileSizeAnimatedImage = UInt(25 * 1024 * 1024)
static let kMaxFileSizeImage = UInt(6 * 1024 * 1024)
static let kMaxFileSizeVideo = UInt(100 * 1024 * 1024)
static let kMaxFileSizeAudio = UInt(100 * 1024 * 1024)
static let kMaxFileSizeGeneric = UInt(100 * 1024 * 1024)
// MARK: Constructor
@ -379,7 +379,7 @@ class SignalAttachment: NSObject {
owsFail("\(TAG) Missing expected pasteboard data for UTI: \(dataUTI)")
return nil
}
let dataSource = DataSourceValue(data)
let dataSource = DataSourceValue.dataSource(with:data)
return imageAttachment(dataSource : dataSource, dataUTI : dataUTI, filename: nil)
}
}
@ -389,7 +389,7 @@ class SignalAttachment: NSObject {
owsFail("\(TAG) Missing expected pasteboard data for UTI: \(dataUTI)")
return nil
}
let dataSource = DataSourceValue(data)
let dataSource = DataSourceValue.dataSource(with:data)
return videoAttachment(dataSource : dataSource, dataUTI : dataUTI, filename: nil)
}
}
@ -399,7 +399,7 @@ class SignalAttachment: NSObject {
owsFail("\(TAG) Missing expected pasteboard data for UTI: \(dataUTI)")
return nil
}
let dataSource = DataSourceValue(data)
let dataSource = DataSourceValue.dataSource(with:data)
return audioAttachment(dataSource : dataSource, dataUTI : dataUTI, filename: nil)
}
}
@ -409,7 +409,7 @@ class SignalAttachment: NSObject {
owsFail("\(TAG) Missing expected pasteboard data for UTI: \(dataUTI)")
return nil
}
let dataSource = DataSourceValue(data)
let dataSource = DataSourceValue.dataSource(with:data)
return genericAttachment(dataSource : dataSource, dataUTI : dataUTI, filename: nil)
}
@ -443,7 +443,7 @@ class SignalAttachment: NSObject {
assert(dataSource != nil)
guard let dataSource = dataSource else {
let attachment = SignalAttachment(dataSource : DataSourceValue.empty(), dataUTI: dataUTI, filename: filename)
let attachment = SignalAttachment(dataSource : DataSourceValue.emptyDataSource(), dataUTI: dataUTI, filename: filename)
attachment.error = .missingData
return attachment
}
@ -522,13 +522,13 @@ class SignalAttachment: NSObject {
assert(dataUTI.characters.count > 0)
guard let image = image else {
let attachment = SignalAttachment(dataSource : DataSourceValue.empty(), dataUTI: dataUTI, filename: filename)
let attachment = SignalAttachment(dataSource : DataSourceValue.emptyDataSource(), dataUTI: dataUTI, filename: filename)
attachment.error = .missingData
return attachment
}
// Make a placeholder attachment on which to hang errors if necessary.
let attachment = SignalAttachment(dataSource : DataSourceValue.empty(), dataUTI: dataUTI, filename: filename)
let attachment = SignalAttachment(dataSource : DataSourceValue.emptyDataSource(), dataUTI: dataUTI, filename: filename)
attachment.image = image
Logger.verbose("\(TAG) Writing \(attachment.mimeType) as image/jpeg")
@ -553,8 +553,13 @@ class SignalAttachment: NSObject {
return attachment
}
if jpgImageData.count <= kMaxFileSizeImage {
let recompressedAttachment = SignalAttachment(dataSource : DataSourceValue(jpgImageData), dataUTI: kUTTypeJPEG as String, filename: filename)
guard let dataSource = DataSourceValue.dataSource(with:jpgImageData) else {
attachment.error = .couldNotConvertToJpeg
return attachment
}
if UInt(jpgImageData.count) <= kMaxFileSizeImage {
let recompressedAttachment = SignalAttachment(dataSource : dataSource, dataUTI: kUTTypeJPEG as String, filename: filename)
recompressedAttachment.image = dstImage
return recompressedAttachment
}
@ -653,9 +658,9 @@ class SignalAttachment: NSObject {
// NOTE: The attachment returned by this method may not be valid.
// Check the attachment's error property.
private class func oversizeTextAttachment(text: String?) -> SignalAttachment {
var dataSource = DataSourceValue.empty()
var dataSource: DataSource? = DataSourceValue.emptyDataSource()
if let data = text?.data(using: .utf8) {
dataSource = DataSourceValue(data)
dataSource = DataSourceValue.dataSource(with:data)
}
return newAttachment(dataSource : dataSource,
dataUTI : kOversizeTextAttachmentUTI,
@ -705,7 +710,7 @@ class SignalAttachment: NSObject {
}
public class func empty() -> SignalAttachment {
return SignalAttachment.attachment(dataSource : DataSourceValue.empty(),
return SignalAttachment.attachment(dataSource : DataSourceValue.emptyDataSource(),
dataUTI: kUTTypeContent as String,
filename:nil)
}
@ -715,13 +720,13 @@ class SignalAttachment: NSObject {
private class func newAttachment(dataSource: DataSource?,
dataUTI: String,
validUTISet: Set<String>?,
maxFileSize: Int,
maxFileSize: UInt,
filename: String?) -> SignalAttachment {
assert(dataUTI.characters.count > 0)
assert(dataSource != nil)
guard let dataSource = dataSource else {
let attachment = SignalAttachment(dataSource : DataSourceValue.empty(), dataUTI: dataUTI, filename: filename)
let attachment = SignalAttachment(dataSource : DataSourceValue.emptyDataSource(), dataUTI: dataUTI, filename: filename)
attachment.error = .missingData
return attachment
}

View file

@ -49,6 +49,7 @@
#import <SignalServiceKit/Contact.h>
#import <SignalServiceKit/ContactsUpdater.h>
#import <SignalServiceKit/Cryptography.h>
#import <SignalServiceKit/DataSource.h>
#import <SignalServiceKit/MIMETypeUtil.h>
#import <SignalServiceKit/NSData+Base64.h>
#import <SignalServiceKit/NSData+Image.h>

View file

@ -1673,7 +1673,8 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
BOOL didAddToProfileWhitelist = [ThreadUtil addThreadToProfileWhitelistIfEmptyContactThread:self.thread];
TSOutgoingMessage *message;
if ([text lengthOfBytesUsingEncoding:NSUTF8StringEncoding] >= kOversizeTextMessageSizeThreshold) {
DataSourceValue *dataSource = [[DataSourceValue alloc] init:[text dataUsingEncoding:NSUTF8StringEncoding]];
id<DataSource> _Nullable dataSource =
[DataSourceValue dataSourceWithData:[text dataUsingEncoding:NSUTF8StringEncoding]];
SignalAttachment *attachment =
[SignalAttachment attachmentWithDataSource:dataSource
dataUTI:SignalAttachment.kOversizeTextAttachmentUTI
@ -3208,7 +3209,7 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
OWSAssert(type);
OWSAssert(filename);
DataSourceUrl *dataSource = [[DataSourceUrl alloc] init:url];
id<DataSource> _Nullable dataSource = [DataSourcePath dataSourceWithURL:url];
SignalAttachment *attachment =
[SignalAttachment attachmentWithDataSource:dataSource dataUTI:type filename:filename];
[self tryToSendAttachmentIfApproved:attachment];
@ -3376,7 +3377,7 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
}
OWSAssert([NSThread isMainThread]);
DataSourceValue *dataSource = [[DataSourceValue alloc] init:imageData];
id<DataSource> _Nullable dataSource = [DataSourceValue dataSourceWithData:imageData];
SignalAttachment *attachment =
[SignalAttachment attachmentWithDataSource:dataSource dataUTI:dataUTI filename:filename];
[self dismissViewControllerAnimated:YES
@ -3451,7 +3452,7 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
exportSession.outputURL = compressedVideoUrl;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
dispatch_async(dispatch_get_main_queue(), ^{
DataSourceUrl *dataSource = [[DataSourceUrl alloc] init:compressedVideoUrl];
id<DataSource> _Nullable dataSource = [DataSourcePath dataSourceWithURL:compressedVideoUrl];
SignalAttachment *attachment = [SignalAttachment attachmentWithDataSource:dataSource
dataUTI:(NSString *)kUTTypeMPEG4
filename:filename];
@ -3828,7 +3829,7 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
return;
}
DataSourceUrl *dataSource = [[DataSourceUrl alloc] init:self.audioRecorder.url];
id<DataSource> _Nullable dataSource = [DataSourcePath dataSourceWithURL:self.audioRecorder.url];
self.audioRecorder = nil;
NSString *filename = [NSLocalizedString(@"VOICE_MESSAGE_FILE_NAME", @"Filename for voice messages.")

View file

@ -328,7 +328,7 @@ NS_ASSUME_NONNULL_BEGIN
OWSMessageSender *messageSender = [Environment getCurrent].messageSender;
NSString *filename = [filePath lastPathComponent];
NSString *utiType = [MIMETypeUtil utiTypeForFileExtension:filename.pathExtension];
DataSourcePath *dataSource = [[DataSourcePath alloc] init:filePath];
id<DataSource> _Nullable dataSource = [DataSourcePath dataSourceWithFilePath:filePath];
SignalAttachment *attachment =
[SignalAttachment attachmentWithDataSource:dataSource dataUTI:utiType filename:filename];
OWSAssert(attachment);
@ -588,7 +588,8 @@ NS_ASSUME_NONNULL_BEGIN
@"lorem, in rhoncus nisi."];
}
DataSourceValue *dataSource = [[DataSourceValue alloc] init:[message dataUsingEncoding:NSUTF8StringEncoding]];
id<DataSource> _Nullable dataSource =
[DataSourceValue dataSourceWithData:[message dataUsingEncoding:NSUTF8StringEncoding]];
SignalAttachment *attachment =
[SignalAttachment attachmentWithDataSource:dataSource
dataUTI:SignalAttachment.kOversizeTextAttachmentUTI
@ -616,7 +617,7 @@ NS_ASSUME_NONNULL_BEGIN
+ (void)sendRandomAttachment:(TSThread *)thread uti:(NSString *)uti length:(NSUInteger)length
{
OWSMessageSender *messageSender = [Environment getCurrent].messageSender;
DataSourceValue *dataSource = [[DataSourceValue alloc] init:[self createRandomNSDataOfSize:length]];
id<DataSource> _Nullable dataSource = [DataSourceValue dataSourceWithData:[self createRandomNSDataOfSize:length]];
SignalAttachment *attachment = [SignalAttachment attachmentWithDataSource:dataSource dataUTI:uti filename:nil];
[ThreadUtil sendMessageWithAttachment:attachment inThread:thread messageSender:messageSender ignoreErrors:YES];
}

View file

@ -0,0 +1,75 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
NS_ASSUME_NONNULL_BEGIN
// A protocol that abstracts away a source of NSData
// and allows us to:
//
// * Lazy-load if possible.
// * Avoid duplicate reads & writes.
@protocol DataSource
// Should not be called unless necessary as it can involve an expensive read.
- (NSData *)data;
// The URL for the data. Should always be a File URL.
//
// Should not be called unless necessary as it can involve an expensive write.
//
// Will only return nil in the error case.
//
// TODO: Try to remove the parameter.
- (nullable NSURL *)dataUrl:(NSString *)fileExtension;
// The file path for the data.
//
// Should not be called unless necessary as it can involve an expensive write.
//
// Will only return nil in the error case.
//
// TODO: Try to remove the parameter.
- (nullable NSString *)dataPath:(NSString *)fileExtension;
// The file path for the data, if it already exists on disk.
//
// This method is safe to call as it will not do any expensive reads or writes.
//
// May return nil if the data does not reside on disk.
- (nullable NSString *)dataPathIfOnDisk;
// Will return zero in the error case.
- (NSUInteger)dataLength;
@end
#pragma mark -
@interface DataSourceValue : NSObject <DataSource>
+ (nullable id<DataSource>)dataSourceWithData:(NSData *)data;
+ (id<DataSource>)emptyDataSource;
@end
#pragma mark -
@interface DataSourcePath : NSObject <DataSource>
+ (nullable id<DataSource>)dataSourceWithURL:(NSURL *)fileUrl;
+ (nullable id<DataSource>)dataSourceWithFilePath:(NSString *)filePath;
@end
//#pragma mark -
//
//@interface DataSourceURL : NSObject <DataSource>
//
//+ (id<DataSource>)dataSourceWithURL:(NSURL *)fileUrl;
//
//@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,436 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "DataSource.h"
NS_ASSUME_NONNULL_BEGIN
@interface DataSourceValue ()
@property (nonatomic) NSData *dataValue;
// This property is lazy-populated.
@property (nonatomic) NSString *cachedFilePath;
@end
#pragma mark -
@implementation DataSourceValue
+ (nullable id<DataSource>)dataSourceWithData:(NSData *)data
{
OWSAssert(data);
if (!data) {
return nil;
}
DataSourceValue *instance = [DataSourceValue new];
instance.dataValue = data;
return instance;
}
+ (id<DataSource>)emptyDataSource
{
return [self dataSourceWithData:[NSData new]];
}
- (NSData *)data
{
OWSAssert(self.dataValue);
return self.dataValue;
}
- (nullable NSURL *)dataUrl:(NSString *)fileExtension
{
NSString *_Nullable path = [self dataPath:fileExtension];
return (path ? [NSURL fileURLWithPath:path] : nil);
}
- (nullable NSString *)dataPath:(NSString *)fileExtension
{
OWSAssert(self.dataValue);
@synchronized(self)
{
if (!self.cachedFilePath) {
NSString *dirPath = NSTemporaryDirectory();
NSString *fileName = [[[NSUUID UUID] UUIDString] stringByAppendingPathExtension:fileExtension];
NSString *filePath = [dirPath stringByAppendingPathComponent:fileName];
if ([self.dataValue writeToFile:fileName atomically:YES]) {
self.cachedFilePath = filePath;
} else {
OWSFail(@"%@ Could not write data to disk: %@", self.tag, fileExtension);
}
}
return self.cachedFilePath;
}
}
- (nullable NSString *)dataPathIfOnDisk
{
return self.cachedFilePath;
}
- (NSUInteger)dataLength
{
OWSAssert(self.dataValue);
return self.dataValue.length;
}
#pragma mark - Logging
+ (NSString *)tag
{
return [NSString stringWithFormat:@"[%@]", self.class];
}
- (NSString *)tag
{
return self.class.tag;
}
@end
#pragma mark -
@interface DataSourcePath ()
@property (nonatomic) NSString *filePath;
// These properties are lazy-populated.
@property (nonatomic) NSData *cachedData;
@property (nonatomic) NSNumber *cachedDataLength;
@end
#pragma mark -
@implementation DataSourcePath
+ (nullable id<DataSource>)dataSourceWithURL:(NSURL *)fileUrl;
{
OWSAssert(fileUrl);
if (!fileUrl || ![fileUrl isFileURL]) {
return nil;
}
DataSourcePath *instance = [DataSourcePath new];
instance.filePath = fileUrl.path;
return instance;
}
+ (nullable id<DataSource>)dataSourceWithFilePath:(NSString *)filePath;
{
OWSAssert(filePath);
if (!filePath) {
return nil;
}
DataSourcePath *instance = [DataSourcePath new];
instance.filePath = filePath;
return instance;
}
- (NSData *)data
{
OWSAssert(self.filePath);
@synchronized(self)
{
if (!self.cachedData) {
self.cachedData = [NSData dataWithContentsOfFile:self.filePath];
}
if (!self.cachedData) {
OWSFail(@"%@ Could not read data from disk: %@", self.tag, self.filePath);
self.cachedData = [NSData new];
}
return self.cachedData;
}
}
- (nullable NSURL *)dataUrl:(NSString *)fileExtension
{
OWSAssert(self.filePath);
return [NSURL fileURLWithPath:self.filePath];
}
- (nullable NSString *)dataPath:(NSString *)fileExtension
{
OWSAssert(self.filePath);
return self.filePath;
}
- (nullable NSString *)dataPathIfOnDisk
{
OWSAssert(self.filePath);
return self.filePath;
}
- (NSUInteger)dataLength
{
OWSAssert(self.filePath);
@synchronized(self)
{
if (!self.cachedDataLength) {
NSError *error;
NSDictionary<NSFileAttributeKey, id> *_Nullable attributes =
[[NSFileManager defaultManager] attributesOfItemAtPath:self.filePath error:&error];
if (!attributes || error) {
OWSFail(@"%@ Could not read data length from disk: %@", self.tag, self.filePath);
self.cachedDataLength = @(0);
} else {
uint64_t fileSize = [attributes fileSize];
self.cachedDataLength = @(fileSize);
}
}
return [self.cachedDataLength unsignedIntegerValue];
}
}
#pragma mark - Logging
+ (NSString *)tag
{
return [NSString stringWithFormat:@"[%@]", self.class];
}
- (NSString *)tag
{
return self.class.tag;
}
@end
//#pragma mark -
//
//@interface DataSourceURL ()
//
//@property (nonatomic) NSURL *fileUrl;
//
//// These properties are lazy-populated.
//@property (nonatomic) NSData *cachedData;
//@property (nonatomic) NSNumber *cachedDataLength;
//
//@end
//
//#pragma mark -
//
//@implementation DataSourceURL
//
//+ (id<DataSource>)dataSourceWithURL:(NSURL *)fileUrl;
//{
// DataSourceValue *instance = [DataSourceValue new];
// instance.fileUrl = fileUrl;
// return instance;
//}
//
//- (NSData *)data
//{
// OWSAssert(self.filePath);
//
// @synchronized (self) {
// if (!self.cachedData) {
// self.cachedData = [NSData dataWithContentsOfFile:self.filePath];
// }
// if (!self.cachedData) {
// OWSFail(@"%@ Could not read data from disk: %@", self.tag, self.filePath);
// self.cachedData = [NSData new];
// }
// return self.cachedData;
// }
//}
//
//- (nullable NSURL *)dataUrl:(NSString *)fileExtension
//{
// OWSAssert(self.filePath);
//
// return [NSURL fileURLWithPath:self.filePath];
//}
//
//- (nullable NSString *)dataPath:(NSString *)fileExtension
//{
// OWSAssert(self.filePath);
//
// return self.filePath;
//}
//
//- (nullable NSString *)dataPathIfOnDisk
//{
// OWSAssert(self.filePath);
//
// return self.filePath;
//}
//
//- (NSUInteger)dataLength
//{
// OWSAssert(self.filePath);
//
// @synchronized (self) {
// if (!self.cachedDataLength) {
// NSError *error;
// NSDictionary<NSFileAttributeKey, id> *_Nullable attributes =
// [[NSFileManager defaultManager] attributesOfItemAtPath:self.filePath error:&error];
// if (!attributes || error) {
// OWSFail(@"%@ Could not read data length from disk: %@", self.tag, self.filePath);
// self.cachedDataLength = @(0);
// } else {
// uint64_t fileSize = [attributes fileSize];
// self.cachedDataLength = @(fileSize);
// }
// }
// return [self.cachedDataLength unsignedIntegerValue];
// }
//}
//
//#pragma mark - Logging
//
//+ (NSString *)tag
//{
// return [NSString stringWithFormat:@"[%@]", self.class];
//}
//
//- (NSString *)tag
//{
// return self.class.tag;
//}
//
//@end
//
//#pragma mark -
//
//
//@objc class DataSourcePath : NSObject, DataSource {
// static let TAG = "[DataSourcePath]"
//
// private let path : String
//
// private var cachedData : Data
// ?
//
// private var cachedLength
// : Int
// ?
//
// // MARK: Constructor
//
// internal required init(_ path
// : String){ self.path = path super.init() }
//
// func
// data()
// ->Data
// {
// if
// let cachedData
// = cachedData{ return cachedData } Logger.error("\(DataSourcePath.TAG) reading data: \(path)") do
// {
// try
// cachedData = NSData(contentsOfFile : path) as Data
// }
// catch
// {
// owsFail("\(DataSourcePath.TAG) Could not read data from disk: \(path)") cachedData = Data()
// }
// return cachedData !
// }
//
// return cachedLength !
// }
//}
//
//@objc class DataSourceUrl : NSObject,
// DataSource {
// static let TAG = "[DataSourceUrl]"
//
// private let url : URL
//
// private var cachedData : Data
// ?
//
// private var cachedLength
// : Int
// ?
//
// // MARK: Constructor
//
// internal required
// init(_ url
// : URL)
// {
// if
// !url.isFileURL{ owsFail("\(DataSourceUrl.TAG) URL is not a file URL: \(url)") } self.url = url
// super.init()
// }
//
// func data()->Data
// {
// if
// let cachedData
// = cachedData{ return cachedData } guard url
// .isFileURL else {
// owsFail("\(DataSourceUrl.TAG) URL is not a file URL: \(url)") return Data()
// } Logger.error("\(DataSourceUrl.TAG) reading data: \(url)") do
// {
// try
// cachedData = Data(contentsOf : url)
// }
// catch
// {
// owsFail("\(DataSourceUrl.TAG) Could not read data from disk: \(url)") cachedData = Data()
// }
// return cachedData !
// }
//
// func dataUrl(fileExtension
// : String)
// ->URL
// ? { return url }
//
// func dataPath(fileExtension
// : String)
// ->String
// ? { guard url
// .isFileURL else {
// owsFail("\(DataSourceUrl.TAG) URL is not a file URL: \(url)") return nil } return url.path }
//
// func dataPathIfOnDisk()
// ->String
// ? { guard url
// .isFileURL else {
// owsFail("\(DataSourceUrl.TAG) URL is not a file URL: \(url)") return nil } return url.path }
//
// func dataLength()
// ->Int
// {
// if
// let cachedLength = cachedLength{ return cachedLength } guard url.isFileURL else
// {
// owsFail("\(DataSourceUrl.TAG) URL is not a file URL: \(url)") return 0
// }
//
// do {
// let fileAttributes = try
// FileManager.default.attributesOfItem(atPath
// : url.path) let fileSize
// = fileAttributes[FileAttributeKey.size] as !UInt64 cachedLength = Int(fileSize)
// }
// catch
// {
// owsFail("\(DataSourceUrl.TAG) Could not read data length from disk: \(url)") cachedLength = 0
// }
//
// return cachedLength !
// }
//}
NS_ASSUME_NONNULL_END