Преглед на файлове

allow to drag and drop any files, keep file name

cyberta преди 2 години
родител
ревизия
d5f810f460

+ 0 - 16
deltachat-ios.xcodeproj/project.pbxproj

@@ -103,8 +103,6 @@
 		30B2BD02278F1C1900889AA4 /* KeychainManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3011E8042787365D00214221 /* KeychainManager.swift */; };
 		30C0D49D237C4908008E2A0E /* CertificateCheckController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30C0D49C237C4908008E2A0E /* CertificateCheckController.swift */; };
 		30C2BFFE27032375005505DA /* ChatSearchAccessoryBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30C2BFFD27032375005505DA /* ChatSearchAccessoryBar.swift */; };
-		30C67BE428D0EB4A0090E162 /* FileType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30C67BE328D0EB4A0090E162 /* FileType.swift */; };
-		30C67BE728D0EC0E0090E162 /* Swime.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30C67BE628D0EC0E0090E162 /* Swime.swift */; };
 		30DAF71C275901610073C154 /* SettingsBackgroundSelectionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30DAF71B275901610073C154 /* SettingsBackgroundSelectionController.swift */; };
 		30E348DF24F3F819005C93D1 /* ChatTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30E348DE24F3F819005C93D1 /* ChatTableView.swift */; };
 		30E348E124F53772005C93D1 /* ImageTextCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30E348E024F53772005C93D1 /* ImageTextCell.swift */; };
@@ -382,8 +380,6 @@
 		30B0ACF924AB5B99004D5E29 /* SettingsEphemeralMessageController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsEphemeralMessageController.swift; sourceTree = "<group>"; };
 		30C0D49C237C4908008E2A0E /* CertificateCheckController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CertificateCheckController.swift; sourceTree = "<group>"; };
 		30C2BFFD27032375005505DA /* ChatSearchAccessoryBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatSearchAccessoryBar.swift; sourceTree = "<group>"; };
-		30C67BE328D0EB4A0090E162 /* FileType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileType.swift; sourceTree = "<group>"; };
-		30C67BE628D0EC0E0090E162 /* Swime.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Swime.swift; sourceTree = "<group>"; };
 		30DAF71B275901610073C154 /* SettingsBackgroundSelectionController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsBackgroundSelectionController.swift; sourceTree = "<group>"; };
 		30E348DE24F3F819005C93D1 /* ChatTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatTableView.swift; sourceTree = "<group>"; };
 		30E348E024F53772005C93D1 /* ImageTextCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageTextCell.swift; sourceTree = "<group>"; };
@@ -709,15 +705,6 @@
 			path = Extensions;
 			sourceTree = "<group>";
 		};
-		30C67BE528D0EBCB0090E162 /* swime */ = {
-			isa = PBXGroup;
-			children = (
-				30C67BE328D0EB4A0090E162 /* FileType.swift */,
-				30C67BE628D0EC0E0090E162 /* Swime.swift */,
-			);
-			path = swime;
-			sourceTree = "<group>";
-		};
 		30E8F2112447285600CE2C90 /* DcShare */ = {
 			isa = PBXGroup;
 			children = (
@@ -984,7 +971,6 @@
 		AE851AC2227C695000ED86F0 /* Helper */ = {
 			isa = PBXGroup;
 			children = (
-				30C67BE528D0EBCB0090E162 /* swime */,
 				30238CFE28A5554C00EF14AC /* FileHelper.swift */,
 				3067AAC52667F3FE00525036 /* ImageFormat.swift */,
 				305702A024C6453700D84EFC /* TypeAlias.swift */,
@@ -1441,7 +1427,6 @@
 				AE9DAF0F22C278C6004C9591 /* ChatTitleView.swift in Sources */,
 				AE4AEE3522B1030D000AA495 /* PreviewController.swift in Sources */,
 				7070FB9B2101ECBB000DC258 /* NewGroupController.swift in Sources */,
-				30C67BE428D0EB4A0090E162 /* FileType.swift in Sources */,
 				3080A037277DE30100E74565 /* UITextView+Extensions.swift in Sources */,
 				3080A027277DE12D00E74565 /* InputBarButtonItem.swift in Sources */,
 				30238CFB28A501C300EF14AC /* WebxdcSelector.swift in Sources */,
@@ -1482,7 +1467,6 @@
 				303492CB257A814200A523D0 /* DraftArea.swift in Sources */,
 				AEE6EC3F2282C59C00EDC689 /* GroupMembersViewController.swift in Sources */,
 				B26B3BC7236DC3DC008ED35A /* SwitchCell.swift in Sources */,
-				30C67BE728D0EC0E0090E162 /* Swime.swift in Sources */,
 				AEE700252438E0E500D6992E /* ProgressAlertHandler.swift in Sources */,
 				30E348E524F6647D005C93D1 /* FileTextCell.swift in Sources */,
 				30238CFD28A5028300EF14AC /* WebxdcGridCell.swift in Sources */,

+ 13 - 5
deltachat-ios/Chat/ChatViewController.swift

@@ -1686,9 +1686,13 @@ class ChatViewController: UITableViewController {
 
     private func stageDocument(url: NSURL) {
         keepKeyboard = true
-        self.draft.setAttachment(viewType: url.pathExtension == "xdc" ? DC_MSG_WEBXDC : DC_MSG_FILE, path: url.relativePath)
-        self.configureDraftArea(draft: self.draft)
-        self.focusInputTextView()
+        DispatchQueue.main.async { [weak self] in
+            guard let self = self else { return }
+            self.draft.setAttachment(viewType: url.pathExtension == "xdc" ? DC_MSG_WEBXDC : DC_MSG_FILE, path: url.relativePath)
+            self.configureDraftArea(draft: self.draft)
+            self.focusInputTextView()
+            FileHelper.deleteFile(atPath: url.relativePath)
+        }
     }
 
     private func stageVideo(url: NSURL) {
@@ -2413,8 +2417,12 @@ extension ChatViewController: ChatInputTextViewPasteDelegate {
         stageImage(image)
     }
 
-    func onVideoDragAndDropped(url: URL) {
-        stageVideo(url: url as NSURL)
+    func onVideoDragAndDropped(url: NSURL) {
+        stageVideo(url: url)
+    }
+
+    func onFileDragAndDropped(url: NSURL) {
+        stageDocument(url: url)
     }
 }
 

+ 83 - 27
deltachat-ios/Chat/Views/ChatInputTextView.swift

@@ -1,6 +1,7 @@
 import Foundation
 import UIKit
 import MobileCoreServices
+import UniformTypeIdentifiers
 
 public class ChatInputTextView: InputTextView {
 
@@ -24,7 +25,20 @@ public class ChatInputTextView: InputTextView {
 
 extension ChatInputTextView: UIDropInteractionDelegate {
     public func dropInteraction(_ interaction: UIDropInteraction, canHandle session: UIDropSession) -> Bool {
-        return  session.items.count == 1 && session.hasItemsConforming(toTypeIdentifiers: [kUTTypeImage as String, kUTTypeText as String, kUTTypeMovie as String, kUTTypeVideo as String])
+        if #available(iOS 14.0, *) {
+            return  session.items.count == 1 && session.hasItemsConforming(toTypeIdentifiers: [
+                UTType.image.identifier,
+                UTType.video.identifier,
+                UTType.movie.identifier,
+                UTType.text.identifier,
+                UTType.item.identifier])
+        }
+        return session.items.count == 1 && session.hasItemsConforming(toTypeIdentifiers: [
+            kUTTypeImage as String,
+            kUTTypeText as String,
+            kUTTypeMovie as String,
+            kUTTypeVideo as String,
+            kUTTypeItem as String])
     }
 
     public func dropInteraction(_ interaction: UIDropInteraction, sessionDidUpdate session: UIDropSession) -> UIDropProposal {
@@ -32,36 +46,77 @@ extension ChatInputTextView: UIDropInteractionDelegate {
     }
 
     public func dropInteraction(_ interaction: UIDropInteraction, performDrop session: UIDropSession) {
-        if session.hasItemsConforming(toTypeIdentifiers: [kUTTypeImage as String]) {
-            session.loadObjects(ofClass: UIImage.self) { [weak self] imageItems in
-                if let images = imageItems as? [UIImage] {
-                    self?.textViewPasteDelegate?.onImageDragAndDropped(image: images[0])
+        if #available(iOS 15.0, *) {
+            if session.hasItemsConforming(toTypeIdentifiers: [UTType.image.identifier]) {
+               loadImageObjects(session: session)
+            } else if session.hasItemsConforming(toTypeIdentifiers: [UTType.movie.identifier, UTType.video.identifier]) {
+                loadFileObjects(session: session, isVideo: true)
+            } else if session.hasItemsConforming(toTypeIdentifiers: [UTType.item.identifier]) {
+                loadFileObjects(session: session)
+            } else if session.hasItemsConforming(toTypeIdentifiers: [UTType.text.identifier]) {
+                loadTextObjects(session: session)
+            }
+        } else {
+            if session.hasItemsConforming(toTypeIdentifiers: [kUTTypeImage as String]) {
+               loadImageObjects(session: session)
+            } else if session.hasItemsConforming(toTypeIdentifiers: [kUTTypeMovie as String, kUTTypeVideo as String]) {
+                loadFileObjects(session: session, isVideo: true)
+            } else if session.hasItemsConforming(toTypeIdentifiers: [kUTTypeItem as String]) {
+                loadFileObjects(session: session)
+            } else if session.hasItemsConforming(toTypeIdentifiers: [kUTTypeText as String]) {
+                loadTextObjects(session: session)
+            }
+        }
+    }
+
+    private func loadImageObjects(session: UIDropSession) {
+        session.loadObjects(ofClass: UIImage.self) { [weak self] imageItems in
+            if let images = imageItems as? [UIImage], !images.isEmpty {
+                self?.textViewPasteDelegate?.onImageDragAndDropped(image: images[0])
+            }
+        }
+    }
+
+    private func loadFileObjects(session: UIDropSession, isVideo: Bool = false) {
+        if session.items.isEmpty {
+            return
+        }
+        let item: UIDragItem = session.items[0]
+        item.itemProvider.loadFileRepresentation(forTypeIdentifier: kUTTypeItem as String) { [weak self] (url, error) in
+            guard let url = url else {
+                if let error = error {
+                    logger.error("error loading file \(error)")
                 }
+                return
             }
-        } else if session.hasItemsConforming(toTypeIdentifiers: [kUTTypeMovie as String, kUTTypeVideo as String]) {
-            session.loadObjects(ofClass: NSData.self) { [weak self] videoItems in
-                if let videos = videoItems as? [NSData] {
-                    let video = videos[0] as Data
-                    if let mimeType = Swime.mimeType(data: video) {
-                        DispatchQueue.global().async { [weak self] in
-                            if let fileName = FileHelper.saveData(data: video, name: "tmp_dragAndDrop", suffix: mimeType.ext, directory: .cachesDirectory) {
-                                DispatchQueue.main.async {
-                                    self?.textViewPasteDelegate?.onVideoDragAndDropped(url: URL(fileURLWithPath: fileName))
-                                }
-                            }
-                        }
+            DispatchQueue.global().async { [weak self] in
+                let nsdata = NSData(contentsOf: url)
+                guard let data = nsdata as? Data else { return }
+                let name = url.deletingPathExtension().lastPathComponent
+                guard let fileName = FileHelper.saveData(data: data,
+                                                         name: name,
+                                                         suffix: url.pathExtension,
+                                                         directory: .cachesDirectory) else { return }
+                DispatchQueue.main.async {
+                    if isVideo {
+                        self?.textViewPasteDelegate?.onVideoDragAndDropped(url: NSURL(fileURLWithPath: fileName))
+                    } else {
+                        self?.textViewPasteDelegate?.onFileDragAndDropped(url: NSURL(fileURLWithPath: fileName))
                     }
                 }
             }
-        } else if session.hasItemsConforming(toTypeIdentifiers: [kUTTypeText as String]) {
-            session.loadObjects(ofClass: String.self) { [weak self] stringItems in
-                if let isEmpty = self?.text.isEmpty, isEmpty {
-                    self?.text = stringItems[0]
-                } else {
-                    var updatedText = self?.text
-                    updatedText?.append(" \(stringItems[0]) ")
-                    self?.text = updatedText
-                }
+        }
+    }
+
+    private func loadTextObjects(session: UIDropSession) {
+        session.loadObjects(ofClass: String.self) { [weak self] stringItems in
+            guard !stringItems.isEmpty else { return }
+            if let isEmpty = self?.text.isEmpty, isEmpty {
+                self?.text = stringItems[0]
+            } else {
+                var updatedText = self?.text
+                updatedText?.append(" \(stringItems[0]) ")
+                self?.text = updatedText
             }
         }
     }
@@ -70,5 +125,6 @@ extension ChatInputTextView: UIDropInteractionDelegate {
 public protocol ChatInputTextViewPasteDelegate: class {
     func onImagePasted(image: UIImage)
     func onImageDragAndDropped(image: UIImage)
-    func onVideoDragAndDropped(url: URL)
+    func onVideoDragAndDropped(url: NSURL)
+    func onFileDragAndDropped(url: NSURL)
 }

+ 0 - 765
deltachat-ios/Helper/swime/FileType.swift

@@ -1,765 +0,0 @@
-import Foundation
-
-// (The MIT License)
-// Copyright (c) 2017 Sendy Halim <sendyhalim93@gmail.com>
-
-
-/// List of type shorthands
-/// with this enum we can check mime type with addition of swift type checker
-/// ```
-/// let swime = Swime(data: data)
-/// swime.type
-/// ```
-public enum FileType {
-  case aac
-  case amr
-  case ar
-  case avi
-  case bmp
-  case bz2
-  case cab
-  case cr2
-  case crx
-  case deb
-  case dmg
-  case eot
-  case epub
-  case exe
-  case flac
-  case flif
-  case flv
-  case gif
-  case gz
-  case ico
-  case jpg
-  case jxr
-  case lz
-  case m4a
-  case m4v
-  case mid
-  case mkv
-  case mov
-  case mp3
-  case mp4
-  case mpg
-  case msi
-  case mxf
-  case nes
-  case ogg
-  case opus
-  case otf
-  case pdf
-  case png
-  case ps
-  case psd
-  case rar
-  case rpm
-  case rtf
-  case sevenZ // 7z, Swift does not let us define enum that starts with a digit
-  case sqlite
-  case swf
-  case tar
-  case tif
-  case ttf
-  case wav
-  case webm
-  case webp
-  case wmv
-  case woff
-  case woff2
-  case xpi
-  case xz
-  case z
-  case zip
-  case heic
-}
-
-public struct MimeType {
-  /// Mime type string representation. For example "application/pdf"
-  public let mime: String
-
-  /// Mime type extension. For example "pdf"
-  public let ext: String
-
-  /// Mime type shorthand representation. For example `.pdf`
-  public let type: FileType
-
-  /// Number of bytes required for `MimeType` to be able to check if the
-  /// given bytes match with its mime type magic number specifications.
-  fileprivate let bytesCount: Int
-
-  /// A function to check if the bytes match the `MimeType` specifications.
-  fileprivate let matches: ([UInt8], Swime) -> Bool
-
-  ///  Check if the given bytes matches with `MimeType`
-  ///  it will check for the `bytes.count` first before delegating the
-  ///  checker function to `matches` property
-  ///
-  ///  - parameter bytes: Bytes represented with `[UInt8]`
-  ///  - parameter swime: Swime instance
-  ///
-  ///  - returns: Bool
-  public func matches(bytes: [UInt8], swime: Swime) -> Bool {
-    return bytes.count >= bytesCount && matches(bytes, swime)
-  }
-
-  /// List of all supported `MimeType`s
-  public static let all: [MimeType] = [
-    MimeType(
-      mime: "audio/aac",
-      ext: "aac",
-      type: .aac,
-      bytesCount: 2,
-      matches: { bytes, _ in
-        return bytes[0...1] == [0xFF, 0xF1]
-      }
-    ),
-    MimeType(
-      mime: "image/jpeg",
-      ext: "jpg",
-      type: .jpg,
-      bytesCount: 3,
-      matches: { bytes, _ in
-        return bytes[0...2] == [0xFF, 0xD8, 0xFF]
-      }
-    ),
-    MimeType(
-      mime: "image/png",
-      ext: "png",
-      type: .png,
-      bytesCount: 4,
-      matches: { bytes, _ in
-        return bytes[0...3] == [0x89, 0x50, 0x4E, 0x47]
-      }
-    ),
-    MimeType(
-      mime: "image/gif",
-      ext: "gif",
-      type: .gif,
-      bytesCount: 3,
-      matches: { bytes, _ in
-        return bytes[0...2] == [0x47, 0x49, 0x46]
-      }
-    ),
-    MimeType(
-      mime: "image/webp",
-      ext: "webp",
-      type: .webp,
-      bytesCount: 12,
-      matches: { bytes, _ in
-        return bytes[8...11] == [0x57, 0x45, 0x42, 0x50]
-      }
-    ),
-    MimeType(
-      mime: "image/flif",
-      ext: "flif",
-      type: .flif,
-      bytesCount: 4,
-      matches: { bytes, _ in
-        return bytes[0...3] == [0x46, 0x4C, 0x49, 0x46]
-      }
-    ),
-    MimeType(
-      mime: "image/x-canon-cr2",
-      ext: "cr2",
-      type: .cr2,
-      bytesCount: 10,
-      matches: { bytes, _ in
-        return (bytes[0...3] == [0x49, 0x49, 0x2A, 0x00] || bytes[0...3] == [0x4D, 0x4D, 0x00, 0x2A]) &&
-          (bytes[8...9] == [0x43, 0x52])
-      }
-    ),
-    MimeType(
-      mime: "image/tiff",
-      ext: "tif",
-      type: .tif,
-      bytesCount: 4,
-      matches: { bytes, _ in
-        return (bytes[0...3] == [0x49, 0x49, 0x2A, 0x00]) ||
-          (bytes[0...3] == [0x4D, 0x4D, 0x00, 0x2A])
-      }
-    ),
-    MimeType(
-      mime: "image/bmp",
-      ext: "bmp",
-      type: .bmp,
-      bytesCount: 2,
-      matches: { bytes, _ in
-        return bytes[0...1] == [0x42, 0x4D]
-      }
-    ),
-    MimeType(
-      mime: "image/vnd.ms-photo",
-      ext: "jxr",
-      type: .jxr,
-      bytesCount: 3,
-      matches: { bytes, _ in
-        return bytes[0...2] == [0x49, 0x49, 0xBC]
-      }
-    ),
-    MimeType(
-      mime: "image/vnd.adobe.photoshop",
-      ext: "psd",
-      type: .psd,
-      bytesCount: 4,
-      matches: { bytes, _ in
-        return bytes[0...3] == [0x38, 0x42, 0x50, 0x53]
-      }
-    ),
-    MimeType(
-      mime: "application/epub+zip",
-      ext: "epub",
-      type: .epub,
-      bytesCount: 58,
-      matches: { bytes, _ in
-        return (bytes[0...3] == [0x50, 0x4B, 0x03, 0x04]) &&
-          (bytes[30...57] == [
-            0x6D, 0x69, 0x6D, 0x65, 0x74, 0x79, 0x70, 0x65, 0x61, 0x70, 0x70, 0x6C,
-            0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x65, 0x70, 0x75, 0x62,
-            0x2B, 0x7A, 0x69, 0x70
-          ])
-      }
-    ),
-
-    // Needs to be before `zip` check
-    // assumes signed .xpi from addons.mozilla.org
-    MimeType(
-      mime: "application/x-xpinstall",
-      ext: "xpi",
-      type: .xpi,
-      bytesCount: 50,
-      matches: { bytes, _ in
-        return (bytes[0...3] == [0x50, 0x4B, 0x03, 0x04]) &&
-        (bytes[30...49] == [
-          0x4D, 0x45, 0x54, 0x41, 0x2D, 0x49, 0x4E, 0x46, 0x2F, 0x6D, 0x6F, 0x7A,
-          0x69, 0x6C, 0x6C, 0x61, 0x2E, 0x72, 0x73, 0x61
-        ])
-      }
-    ),
-    MimeType(
-      mime: "application/zip",
-      ext: "zip",
-      type: .zip,
-      bytesCount: 50,
-      matches: { bytes, _ in
-        return (bytes[0...1] == [0x50, 0x4B]) &&
-          (bytes[2] == 0x3 || bytes[2] == 0x5 || bytes[2] == 0x7) &&
-          (bytes[3] == 0x4 || bytes[3] == 0x6 || bytes[3] == 0x8)
-      }
-    ),
-    MimeType(
-      mime: "application/x-tar",
-      ext: "tar",
-      type: .tar,
-      bytesCount: 262,
-      matches: { bytes, _ in
-        return bytes[257...261] == [0x75, 0x73, 0x74, 0x61, 0x72]
-      }
-    ),
-    MimeType(
-      mime: "application/x-rar-compressed",
-      ext: "rar",
-      type: .rar,
-      bytesCount: 7,
-      matches: { bytes, _ in
-        return (bytes[0...5] == [0x52, 0x61, 0x72, 0x21, 0x1A, 0x07]) &&
-          (bytes[6] == 0x0 || bytes[6] == 0x1)
-      }
-    ),
-    MimeType(
-      mime: "application/gzip",
-      ext: "gz",
-      type: .gz,
-      bytesCount: 3,
-      matches: { bytes, _ in
-        return bytes[0...2] == [0x1F, 0x8B, 0x08]
-      }
-    ),
-    MimeType(
-      mime: "application/x-bzip2",
-      ext: "bz2",
-      type: .bz2,
-      bytesCount: 3,
-      matches: { bytes, _ in
-        return bytes[0...2] == [0x42, 0x5A, 0x68]
-      }
-    ),
-    MimeType(
-      mime: "application/x-7z-compressed",
-      ext: "7z",
-      type: .sevenZ,
-      bytesCount: 6,
-      matches: { bytes, _ in
-        return bytes[0...5] == [0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C]
-      }
-    ),
-    MimeType(
-      mime: "application/x-apple-diskimage",
-      ext: "dmg",
-      type: .dmg,
-      bytesCount: 2,
-      matches: { bytes, _ in
-        return bytes[0...1] == [0x78, 0x01]
-      }
-    ),
-    MimeType(
-      mime: "video/mp4",
-      ext: "mp4",
-      type: .mp4,
-      bytesCount: 28,
-      matches: { bytes, _ in
-        return (bytes[0...2] == [0x00, 0x00, 0x00] && (bytes[3] == 0x18 || bytes[3] == 0x20) && bytes[4...7] == [0x66, 0x74, 0x79, 0x70]) ||
-          (bytes[0...3] == [0x33, 0x67, 0x70, 0x35]) ||
-          (bytes[0...11] == [0x00, 0x00, 0x00, 0x1C, 0x66, 0x74, 0x79, 0x70, 0x6D, 0x70, 0x34, 0x32] &&
-            bytes[16...27] == [0x6D, 0x70, 0x34, 0x31, 0x6D, 0x70, 0x34, 0x32, 0x69, 0x73, 0x6F, 0x6D]) ||
-          (bytes[0...11] == [0x00, 0x00, 0x00, 0x1C, 0x66, 0x74, 0x79, 0x70, 0x69, 0x73, 0x6F, 0x6D]) ||
-          (bytes[0...11] == [0x00, 0x00, 0x00, 0x1C, 0x66, 0x74, 0x79, 0x70, 0x6D, 0x70, 0x34, 0x32])
-      }
-    ),
-    MimeType(
-      mime: "video/x-m4v",
-      ext: "m4v",
-      type: .m4v,
-      bytesCount: 11,
-      matches: { bytes, _ in
-        return bytes[0...10] == [0x00, 0x00, 0x00, 0x1C, 0x66, 0x74, 0x79, 0x70, 0x4D, 0x34, 0x56]
-      }
-    ),
-    MimeType(
-      mime: "audio/midi",
-      ext: "mid",
-      type: .mid,
-      bytesCount: 4,
-      matches: { bytes, _ in
-        return bytes[0...3] == [0x4D, 0x54, 0x68, 0x64]
-      }
-    ),
-    MimeType(
-      mime: "video/x-matroska",
-      ext: "mkv",
-      type: .mkv,
-      bytesCount: 4,
-      matches: { bytes, swime in
-        guard bytes[0...3] == [0x1A, 0x45, 0xDF, 0xA3] else {
-          return false
-        }
-
-        let bytes = Array(swime.readBytes(count: 4100)[4 ..< 4100])
-        var idPos = -1
-
-        for i in 0 ..< (bytes.count - 1) {
-          if bytes[i] == 0x42 && bytes[i + 1] == 0x82 {
-            idPos = i
-            break
-          }
-        }
-
-        guard idPos > -1 else {
-          return false
-        }
-
-        let docTypePos = idPos + 3
-        let findDocType: (String) -> Bool = { type in
-          for i in 0 ..< type.count {
-            let index = type.index(type.startIndex, offsetBy: i)
-            let scalars = String(type[index]).unicodeScalars
-
-            if bytes[docTypePos + i] != UInt8(scalars[scalars.startIndex].value) {
-              return false
-            }
-          }
-
-          return true
-        }
-
-        return findDocType("matroska")
-      }
-    ),
-    MimeType(
-      mime: "video/webm",
-      ext: "webm",
-      type: .webm,
-      bytesCount: 4,
-      matches: { bytes, swime in
-        guard bytes[0...3] == [0x1A, 0x45, 0xDF, 0xA3] else {
-          return false
-        }
-
-        let bytes = Array(swime.readBytes(count: 4100)[4 ..< 4100])
-        var idPos = -1
-
-        for i in 0 ..< (bytes.count - 1) {
-          if bytes[i] == 0x42 && bytes[i + 1] == 0x82 {
-            idPos = i
-            break
-          }
-        }
-
-        guard idPos > -1 else {
-          return false
-        }
-
-        let docTypePos = idPos + 3
-        let findDocType: (String) -> Bool = { type in
-          for i in 0 ..< type.count {
-            let index = type.index(type.startIndex, offsetBy: i)
-            let scalars = String(type[index]).unicodeScalars
-
-            if bytes[docTypePos + i] != UInt8(scalars[scalars.startIndex].value) {
-              return false
-            }
-          }
-
-          return true
-        }
-
-        return findDocType("webm")
-      }
-    ),
-    MimeType(
-      mime: "video/quicktime",
-      ext: "mov",
-      type: .mov,
-      bytesCount: 8,
-      matches: { bytes, _ in
-        return bytes[0...7] == [0x00, 0x00, 0x00, 0x14, 0x66, 0x74, 0x79, 0x70]
-      }
-    ),
-    MimeType(
-      mime: "video/x-msvideo",
-      ext: "avi",
-      type: .avi,
-      bytesCount: 11,
-      matches: { bytes, _ in
-        return (bytes[0...3] == [0x52, 0x49, 0x46, 0x46]) &&
-          (bytes[8...10] == [0x41, 0x56, 0x49])
-      }
-    ),
-    MimeType(
-      mime: "video/x-ms-wmv",
-      ext: "wmv",
-      type: .wmv,
-      bytesCount: 10,
-      matches: { bytes, _ in
-        return bytes[0...9] == [0x30, 0x26, 0xB2, 0x75, 0x8E, 0x66, 0xCF, 0x11, 0xA6, 0xD9]
-      }
-    ),
-    MimeType(
-      mime: "video/mpeg",
-      ext: "mpg",
-      type: .mpg,
-      bytesCount: 4,
-      matches: { bytes, _ in
-        guard bytes[0...2] == [0x00, 0x00, 0x01]  else {
-          return false
-        }
-
-        let hexCode = String(format: "%2X", bytes[3])
-
-        return hexCode.first != nil && hexCode.first! == "B"
-      }
-    ),
-    MimeType(
-      mime: "audio/mpeg",
-      ext: "mp3",
-      type: .mp3,
-      bytesCount: 3,
-      matches: { bytes, _ in
-        return (bytes[0...2] == [0x49, 0x44, 0x33]) ||
-          (bytes[0...1] == [0xFF, 0xFB])
-      }
-    ),
-    MimeType(
-      mime: "audio/m4a",
-      ext: "m4a",
-      type: .m4a,
-      bytesCount: 11,
-      matches: { bytes, _ in
-        return (bytes[0...3] == [0x4D, 0x34, 0x41, 0x20]) ||
-          (bytes[4...10] == [0x66, 0x74, 0x79, 0x70, 0x4D, 0x34, 0x41])
-      }
-    ),
-
-    // Needs to be before `ogg` check
-    MimeType(
-      mime: "audio/opus",
-      ext: "opus",
-      type: .opus,
-      bytesCount: 36,
-      matches: { bytes, _ in
-        return bytes[28...35] == [0x4F, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64]
-      }
-    ),
-    MimeType(
-      mime: "audio/ogg",
-      ext: "ogg",
-      type: .ogg,
-      bytesCount: 4,
-      matches: { bytes, _ in
-        return bytes[0...3] == [0x4F, 0x67, 0x67, 0x53]
-      }
-    ),
-    MimeType(
-      mime: "audio/x-flac",
-      ext: "flac",
-      type: .flac,
-      bytesCount: 4,
-      matches: { bytes, _ in
-        return bytes[0...3] == [0x66, 0x4C, 0x61, 0x43]
-      }
-    ),
-    MimeType(
-      mime: "audio/x-wav",
-      ext: "wav",
-      type: .wav,
-      bytesCount: 12,
-      matches: { bytes, _ in
-        return (bytes[0...3] == [0x52, 0x49, 0x46, 0x46]) &&
-          (bytes[8...11] == [0x57, 0x41, 0x56, 0x45])
-      }
-    ),
-    MimeType(
-      mime: "audio/amr",
-      ext: "amr",
-      type: .amr,
-      bytesCount: 6,
-      matches: { bytes, _ in
-        return bytes[0...5] == [0x23, 0x21, 0x41, 0x4D, 0x52, 0x0A]
-      }
-    ),
-    MimeType(
-      mime: "application/pdf",
-      ext: "pdf",
-      type: .pdf,
-      bytesCount: 4,
-      matches: { bytes, _ in
-        return bytes[0...3] == [0x25, 0x50, 0x44, 0x46]
-      }
-    ),
-    MimeType(
-      mime: "application/x-msdownload",
-      ext: "exe",
-      type: .exe,
-      bytesCount: 2,
-      matches: { bytes, _ in
-        return bytes[0...1] == [0x4D, 0x5A]
-      }
-    ),
-    MimeType(
-      mime: "application/x-shockwave-flash",
-      ext: "swf",
-      type: .swf,
-      bytesCount: 3,
-      matches: { bytes, _ in
-        return (bytes[0] == 0x43 || bytes[0] == 0x46) && (bytes[1...2] == [0x57, 0x53])
-      }
-    ),
-    MimeType(
-      mime: "application/rtf",
-      ext: "rtf",
-      type: .rtf,
-      bytesCount: 5,
-      matches: { bytes, _ in
-        return bytes[0...4] == [0x7B, 0x5C, 0x72, 0x74, 0x66]
-      }
-    ),
-    MimeType(
-      mime: "application/font-woff",
-      ext: "woff",
-      type: .woff,
-      bytesCount: 8,
-      matches: { bytes, _ in
-        return (bytes[0...3] == [0x77, 0x4F, 0x46, 0x46]) &&
-          ((bytes[4...7] == [0x00, 0x01, 0x00, 0x00]) || (bytes[4...7] == [0x4F, 0x54, 0x54, 0x4F]))
-      }
-    ),
-    MimeType(
-      mime: "application/font-woff",
-      ext: "woff2",
-      type: .woff2,
-      bytesCount: 8,
-      matches: { bytes, _ in
-        return (bytes[0...3] == [0x77, 0x4F, 0x46,  0x32]) &&
-          ((bytes[4...7] == [0x00, 0x01, 0x00, 0x00]) || (bytes[4...7] == [0x4F, 0x54, 0x54, 0x4F]))
-      }
-    ),
-    MimeType(
-      mime: "application/vnd.ms-fontobject",
-      ext: "eot",
-      type: .eot,
-      bytesCount: 82,
-      matches: { bytes, _ in
-        return bytes[34...35] == [0x4c, 0x50] &&
-        Array(bytes[64...79]) == Array(repeating: 0x00, count: 16) &&
-        bytes[82] != 0x00
-      }
-    ),
-    MimeType(
-      mime: "application/font-sfnt",
-      ext: "ttf",
-      type: .ttf,
-      bytesCount: 5,
-      matches: { bytes, _ in
-        return bytes[0...4] == [0x00, 0x01, 0x00, 0x00, 0x00]
-      }
-    ),
-    MimeType(
-      mime: "application/font-sfnt",
-      ext: "otf",
-      type: .otf,
-      bytesCount: 5,
-      matches: { bytes, _ in
-        return bytes[0...4] == [0x4F, 0x54, 0x54, 0x4F, 0x00]
-      }
-    ),
-    MimeType(
-      mime: "image/x-icon",
-      ext: "ico",
-      type: .ico,
-      bytesCount: 4,
-      matches: { bytes, _ in
-        return bytes[0...3] == [0x00, 0x00, 0x01, 0x00]
-      }
-    ),
-    MimeType(
-      mime: "video/x-flv",
-      ext: "flv",
-      type: .flv,
-      bytesCount: 4,
-      matches: { bytes, _ in
-        return bytes[0...3] == [0x46, 0x4C, 0x56, 0x01]
-      }
-    ),
-    MimeType(
-      mime: "application/postscript",
-      ext: "ps",
-      type: .ps,
-      bytesCount: 2,
-      matches: { bytes, _ in
-        return bytes[0...1] == [0x25, 0x21]
-      }
-    ),
-    MimeType(
-      mime: "application/x-xz",
-      ext: "xz",
-      type: .xz,
-      bytesCount: 6,
-      matches: { bytes, _ in
-        return bytes[0...5] == [0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00]
-      }
-    ),
-    MimeType(
-      mime: "application/x-sqlite3",
-      ext: "sqlite",
-      type: .sqlite,
-      bytesCount: 4,
-      matches: { bytes, _ in
-        return bytes[0...3] == [0x53, 0x51, 0x4C, 0x69]
-      }
-    ),
-    MimeType(
-      mime: "application/x-nintendo-nes-rom",
-      ext: "nes",
-      type: .nes,
-      bytesCount: 4,
-      matches: { bytes, _ in
-        return bytes[0...3] == [0x4E, 0x45, 0x53, 0x1A]
-      }
-    ),
-    MimeType(
-      mime: "application/x-google-chrome-extension",
-      ext: "crx",
-      type: .crx,
-      bytesCount: 4,
-      matches: { bytes, _ in
-        return bytes[0...3] == [0x43, 0x72, 0x32, 0x34]
-      }
-    ),
-    MimeType(
-      mime: "application/vnd.ms-cab-compressed",
-      ext: "cab",
-      type: .cab,
-      bytesCount: 4,
-      matches: { bytes, _ in
-        return (bytes[0...3] == [0x4D, 0x53, 0x43, 0x46]) || (bytes[0...3] == [0x49, 0x53, 0x63, 0x28])
-      }
-    ),
-
-    // Needs to be before `ar` check
-    MimeType(
-      mime: "application/x-deb",
-      ext: "deb",
-      type: .deb,
-      bytesCount: 21,
-      matches: { bytes, _ in
-        return bytes[0...20] == [
-          0x21, 0x3C, 0x61, 0x72, 0x63, 0x68, 0x3E, 0x0A, 0x64, 0x65, 0x62, 0x69,
-          0x61, 0x6E, 0x2D, 0x62, 0x69, 0x6E, 0x61, 0x72, 0x79
-        ]
-      }
-    ),
-    MimeType(
-      mime: "application/x-unix-archive",
-      ext: "ar",
-      type: .ar,
-      bytesCount: 7,
-      matches: { bytes, _ in
-        return bytes[0...6] == [0x21, 0x3C, 0x61, 0x72, 0x63, 0x68, 0x3E]
-      }
-    ),
-    MimeType(
-      mime: "application/x-rpm",
-      ext: "rpm",
-      type: .rpm,
-      bytesCount: 4,
-      matches: { bytes, _ in
-        return bytes[0...3] == [0xED, 0xAB, 0xEE, 0xDB]
-      }
-    ),
-    MimeType(
-      mime: "application/x-compress",
-      ext: "Z",
-      type: .z,
-      bytesCount: 2,
-      matches: { bytes, _ in
-        return (bytes[0...1] == [0x1F, 0xA0]) || (bytes[0...1] == [0x1F, 0x9D])
-      }
-    ),
-    MimeType(
-      mime: "application/x-lzip",
-      ext: "lz",
-      type: .lz,
-      bytesCount: 4,
-      matches: { bytes, _ in
-        return bytes[0...3] == [0x4C, 0x5A, 0x49, 0x50]
-      }
-    ),
-    MimeType(
-      mime: "application/x-msi",
-      ext: "msi",
-      type: .msi,
-      bytesCount: 8,
-      matches: { bytes, _ in
-        return bytes[0...7] == [0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1]
-      }
-    ),
-    MimeType(
-      mime: "application/mxf",
-      ext: "mxf",
-      type: .mxf,
-      bytesCount: 14,
-      matches: { bytes, _ in
-        return bytes[0...13] == [0x06, 0x0E, 0x2B, 0x34, 0x02, 0x05, 0x01, 0x01, 0x0D, 0x01, 0x02, 0x01, 0x01, 0x02 ]
-      }
-    ),
-    MimeType(
-        mime: "application/heic",
-        ext: "heic",
-        type: .heic,
-        bytesCount: 12,
-        matches: { bytes, _ in
-            return bytes[8...11] == [0x68, 0x65, 0x69, 0x63] || bytes[8...11] == [0x68, 0x65, 0x69, 0x78]
-        }
-    )
-  ]
-}

+ 0 - 59
deltachat-ios/Helper/swime/Swime.swift

@@ -1,59 +0,0 @@
-import Foundation
-// (The MIT License)
-// Copyright (c) 2017 Sendy Halim <sendyhalim93@gmail.com>
-
-
-public struct Swime {
-  /// File data
-  let data: Data
-
-  ///  A static method to get the `MimeType` that matches the given file data
-  ///
-  ///  - returns: Optional<MimeType>
-  static public func mimeType(data: Data) -> MimeType? {
-    return mimeType(swime: Swime(data: data))
-  }
-
-  ///  A static method to get the `MimeType` that matches the given bytes
-  ///
-  ///  - returns: Optional<MimeType>
-  static public func mimeType(bytes: [UInt8]) -> MimeType? {
-    return mimeType(swime: Swime(bytes: bytes))
-  }
-
-  ///  Get the `MimeType` that matches the given `Swime` instance
-  ///
-  ///  - returns: Optional<MimeType>
-  static public func mimeType(swime: Swime) -> MimeType? {
-    let bytes = swime.readBytes(count: min(swime.data.count, 262))
-
-    for mime in MimeType.all {
-      if mime.matches(bytes: bytes, swime: swime) {
-        return mime
-      }
-    }
-
-    return nil
-  }
-
-  public init(data: Data) {
-    self.data = data
-  }
-
-  public init(bytes: [UInt8]) {
-    self.init(data: Data(bytes))
-  }
-
-  ///  Read bytes from file data
-  ///
-  ///  - parameter count: Number of bytes to be read
-  ///
-  ///  - returns: Bytes represented with `[UInt8]`
-  internal func readBytes(count: Int) -> [UInt8] {
-    var bytes = [UInt8](repeating: 0, count: count)
-
-    data.copyBytes(to: &bytes, count: count)
-
-    return bytes
-  }
-}