Compare commits

..

7 Commits

Author SHA1 Message Date
Amir Abbas 528d5eebc3 Fixed relativePath(of:) crash 2017-03-18 15:58:44 +03:30
Amir Abbas 079f8f4b77 Refactored methods to extensions 2017-03-17 15:52:58 +03:30
Amir Abbas e12f386a9d Refactored DispatchTime, better ExposureTime calculation 2017-03-11 03:02:02 +03:30
Amir Abbas 38e217bc19 Better LocalFileObject initialization with empty path 2017-03-09 17:34:00 +03:30
Amir Abbas 0b41abd4ef Optimized PDF thumbnail/meta handling
- Fixed ISO speed and GPS Area image meta
- Fixed Dropbox `name ! BEGINSWiTH %` search query
2017-03-01 13:28:44 +03:30
Amir Abbas aa781adeb2 Fixed searchFiles() from string, fixing “BEGINSWITH” typo 2017-02-24 16:53:59 +03:30
Amir Abbas d61e51ba1c Fixes #29 (WebDAV authentication), minor lints/optimiziations 2017-02-24 16:24:34 +03:30
22 changed files with 440 additions and 397 deletions
+2 -2
View File
@@ -17,7 +17,7 @@ env:
- DESTINATION="OS=8.1,name=iPhone 4S" SCHEME="$IOS_FRAMEWORK_SCHEME" SDK="$IOS_SDK" RUN_TESTS="NO" BUILD_EXAMPLE="NO" POD="NO" CARTHAGEDEPLOY="NO"
- DESTINATION="OS=10.1,name=Apple TV 1080p" SCHEME="$TVOS_FRAMEWORK_SCHEME" SDK="$TVOS_SDK" RUN_TESTS="NO" BUILD_EXAMPLE="NO" POD="NO" CARTHAGEDEPLOY="NO"
- DESTINATION="OS=10.0,name=Apple TV 1080p" SCHEME="$TVOS_FRAMEWORK_SCHEME" SDK="$TVOS_SDK" RUN_TESTS="NO" BUILD_EXAMPLE="NO" POD="NO" CARTHAGEDEPLOY="NO"
# - DESTINATION="OS=10.0,name=Apple TV 1080p" SCHEME="$TVOS_FRAMEWORK_SCHEME" SDK="$TVOS_SDK" RUN_TESTS="NO" BUILD_EXAMPLE="NO" POD="NO" CARTHAGEDEPLOY="NO"
- DESTINATION="arch=x86_64" SCHEME="$MACOS_FRAMEWORK_SCHEME" SDK="$MACOS_SDK" RUN_TESTS="NO" BUILD_EXAMPLE="NO" POD="NO" CARTHAGEDEPLOY="NO"
before_install:
@@ -50,7 +50,7 @@ script:
# Run `pod lib lint` if specified
- if [ $POD == "YES" ]; then
pod lib lint;
pod lib lint --quick;
fi
after_success:
+1 -1
View File
@@ -16,7 +16,7 @@ Pod::Spec.new do |s|
#
s.name = "FileProvider"
s.version = "0.14.1"
s.version = "0.14.4"
s.summary = "FileManager replacement for Local and Remote (WebDAV/Dropbox/OneDrive/SMB2) files on iOS and macOS."
# This description is used to generate tags and improve search results.
+10 -2
View File
@@ -47,6 +47,9 @@
794C220E1D591A4B00EC49B8 /* SMB2QueryTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 794C220D1D591A4B00EC49B8 /* SMB2QueryTypes.swift */; };
794C220F1D591A4B00EC49B8 /* SMB2QueryTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 794C220D1D591A4B00EC49B8 /* SMB2QueryTypes.swift */; };
794C22101D591A4B00EC49B8 /* SMB2QueryTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 794C220D1D591A4B00EC49B8 /* SMB2QueryTypes.swift */; };
796807551E7BF17E00BBB87B /* FileProviderExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 796807541E7BF17E00BBB87B /* FileProviderExtensions.swift */; };
796807561E7BF17E00BBB87B /* FileProviderExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 796807541E7BF17E00BBB87B /* FileProviderExtensions.swift */; };
796807571E7BF17E00BBB87B /* FileProviderExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 796807541E7BF17E00BBB87B /* FileProviderExtensions.swift */; };
799396AA1D48C02300086753 /* DropboxFileProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396931D48C02300086753 /* DropboxFileProvider.swift */; };
799396AB1D48C02300086753 /* DropboxFileProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396931D48C02300086753 /* DropboxFileProvider.swift */; };
799396AC1D48C02300086753 /* DropboxFileProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799396931D48C02300086753 /* DropboxFileProvider.swift */; };
@@ -134,6 +137,7 @@
794C21FD1D58912A00EC49B8 /* DropboxHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DropboxHelper.swift; sourceTree = "<group>"; };
794C22091D5893F800EC49B8 /* SMB2Notification.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMB2Notification.swift; sourceTree = "<group>"; };
794C220D1D591A4B00EC49B8 /* SMB2QueryTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMB2QueryTypes.swift; sourceTree = "<group>"; };
796807541E7BF17E00BBB87B /* FileProviderExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileProviderExtensions.swift; sourceTree = "<group>"; };
799396671D48B7F600086753 /* FileProvider.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FileProvider.framework; sourceTree = BUILT_PRODUCTS_DIR; };
799396751D48B80D00086753 /* FileProvider.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FileProvider.framework; sourceTree = BUILT_PRODUCTS_DIR; };
799396821D48B82700086753 /* FileProvider.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FileProvider.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -281,6 +285,7 @@
799396991D48C02300086753 /* SMBTypes */,
799396941D48C02300086753 /* FileProvider.h */,
799396951D48C02300086753 /* FileProvider.swift */,
796807541E7BF17E00BBB87B /* FileProviderExtensions.swift */,
79F5745A1DFDB10A00179ABF /* FileObject.swift */,
799396961D48C02300086753 /* LocalFileProvider.swift */,
792572401DF23BDA006A1526 /* LocalHelper.swift */,
@@ -475,6 +480,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
796807551E7BF17E00BBB87B /* FileProviderExtensions.swift in Sources */,
799396B31D48C02300086753 /* LocalFileProvider.swift in Sources */,
799396D41D48C02300086753 /* SMB2Tree.swift in Sources */,
7924B1A21D89DAE000589DB7 /* Options.swift in Sources */,
@@ -515,6 +521,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
796807561E7BF17E00BBB87B /* FileProviderExtensions.swift in Sources */,
799396B41D48C02300086753 /* LocalFileProvider.swift in Sources */,
799396D51D48C02300086753 /* SMB2Tree.swift in Sources */,
7924B1A31D89DAE000589DB7 /* Options.swift in Sources */,
@@ -555,6 +562,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
796807571E7BF17E00BBB87B /* FileProviderExtensions.swift in Sources */,
799396B51D48C02300086753 /* LocalFileProvider.swift in Sources */,
799396D61D48C02300086753 /* SMB2Tree.swift in Sources */,
7924B1A41D89DAE000589DB7 /* Options.swift in Sources */,
@@ -597,7 +605,7 @@
799396601D48B7BF00086753 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_VERSION_STRING = 0.14.1;
BUNDLE_VERSION_STRING = 0.14.4;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
@@ -627,7 +635,7 @@
799396611D48B7BF00086753 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_VERSION_STRING = 0.14.1;
BUNDLE_VERSION_STRING = 0.14.4;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
+1 -1
View File
@@ -107,7 +107,7 @@ For LocalFileProvider if you want to deal with `Documents` folder
let documentsProvider = LocalFileProvider()
// Equals with:
let documentsProvider = LocalFileProvider(directory: .documentDirectory, domainMask: = .userDomainMask)
let documentsProvider = LocalFileProvider(for: .documentDirectory, in: .userDomainMask)
// Equals with:
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
+1 -1
View File
@@ -797,7 +797,7 @@ open class CloudOperationHandle: OperationHandle {
DispatchQueue.main.async {
query.start()
}
_ = group.wait(timeout: DispatchTime.now() + 30)
_ = group.wait(timeout: .now() + 30)
return item
}
}
+17 -17
View File
@@ -110,14 +110,14 @@ open class DropboxFileProvider: FileProviderBasicRemote {
request.setValue("Bearer \(credential?.password ?? "")", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let requestDictionary: [String: AnyObject] = ["path": correctPath(path)! as NSString]
request.httpBody = dictionaryToJSON(requestDictionary)?.data(using: .utf8)
request.httpBody = Data(jsonDictionary: requestDictionary)
let task = session.dataTask(with: request, completionHandler: { (data, response, error) in
var serverError: FileProviderDropboxError?
var fileObject: DropboxFileObject?
if let response = response as? HTTPURLResponse {
let code = FileProviderHTTPErrorCode(rawValue: response.statusCode)
serverError = code != nil ? FileProviderDropboxError(code: code!, path: path, errorDescription: String(data: data ?? Data(), encoding: .utf8)) : nil
if let data = data, let jsonStr = String(data: data, encoding: .utf8), let json = jsonToDictionary(jsonStr), let file = DropboxFileObject(json: json) {
if let json = data?.deserializeJSON(), let file = DropboxFileObject(json: json) {
fileObject = file
}
}
@@ -134,7 +134,7 @@ open class DropboxFileProvider: FileProviderBasicRemote {
let task = session.dataTask(with: request, completionHandler: { (data, response, error) in
var totalSize: Int64 = -1
var usedSize: Int64 = 0
if let data = data, let jsonStr = String(data: data, encoding: .utf8), let json = jsonToDictionary(jsonStr) {
if let json = data?.deserializeJSON() {
totalSize = ((json["allocation"] as? NSDictionary)?["allocated"] as? NSNumber)?.int64Value ?? -1
usedSize = (json["used"] as? NSNumber)?.int64Value ?? 0
}
@@ -232,7 +232,7 @@ extension DropboxFileProvider: FileProviderOperations {
} else {
requestDictionary["path"] = correctPath(sourcePath) as NSString?
}
request.httpBody = dictionaryToJSON(requestDictionary)?.data(using: .utf8)
request.httpBody = Data(jsonDictionary: requestDictionary)
let task = session.dataTask(with: request, completionHandler: { (data, response, error) in
var serverError: FileProviderDropboxError?
if let response = response as? HTTPURLResponse, response.statusCode >= 300, let code = FileProviderHTTPErrorCode(rawValue: response.statusCode) {
@@ -264,7 +264,7 @@ extension DropboxFileProvider: FileProviderOperations {
request.httpMethod = "GET"
request.setValue("Bearer \(credential?.password ?? "")", forHTTPHeaderField: "Authorization")
let requestDictionary: [String: AnyObject] = ["path": path as NSString]
let requestJson = dictionaryToJSON(requestDictionary) ?? ""
let requestJson = String(jsonDictionary: requestDictionary) ?? ""
request.setValue(requestJson, forHTTPHeaderField: "Dropbox-API-Arg")
let task = session.downloadTask(with: request, completionHandler: { (cacheURL, response, error) in
guard let cacheURL = cacheURL, let httpResponse = response as? HTTPURLResponse , httpResponse.statusCode < 300 else {
@@ -307,7 +307,7 @@ extension DropboxFileProvider: FileProviderReadWrite {
request.setValue("bytes=\(offset)-", forHTTPHeaderField: "Range")
}
let requestDictionary: [String: AnyObject] = ["path": correctPath(path)! as NSString]
request.setValue(dictionaryToJSON(requestDictionary), forHTTPHeaderField: "Dropbox-API-Arg")
request.setValue(String(jsonDictionary: requestDictionary), forHTTPHeaderField: "Dropbox-API-Arg")
let task = session.dataTask(with: request, completionHandler: { (data, response, error) in
var serverError: FileProviderDropboxError?
if let httpResponse = response as? HTTPURLResponse , httpResponse.statusCode >= 300, let code = FileProviderHTTPErrorCode(rawValue: httpResponse.statusCode) {
@@ -384,7 +384,7 @@ extension DropboxFileProvider {
request.setValue("Bearer \(credential?.password ?? "")", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let requestDictionary: [String: AnyObject] = ["path": correctPath(path)! as NSString]
request.httpBody = dictionaryToJSON(requestDictionary)?.data(using: .utf8)
request.httpBody = Data(jsonDictionary: requestDictionary)
let task = session.dataTask(with: request, completionHandler: { (data, response, error) in
var serverError: FileProviderDropboxError?
var link: URL?
@@ -392,7 +392,7 @@ extension DropboxFileProvider {
if let response = response as? HTTPURLResponse {
let code = FileProviderHTTPErrorCode(rawValue: response.statusCode)
serverError = code != nil ? FileProviderDropboxError(code: code!, path: path, errorDescription: String(data: data ?? Data(), encoding: .utf8)) : nil
if let data = data, let jsonStr = String(data: data, encoding: .utf8), let json = jsonToDictionary(jsonStr) {
if let json = data?.deserializeJSON() {
if let linkStr = json["link"] as? String {
link = URL(string: linkStr)
}
@@ -430,7 +430,7 @@ extension DropboxFileProvider {
request.setValue("Bearer \(credential?.password ?? "")", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let requestDictionary: [String: AnyObject] = ["path": correctPath(toPath)! as NSString, "url" : remoteURL.absoluteString as NSString]
request.httpBody = dictionaryToJSON(requestDictionary)?.data(using: .utf8)
request.httpBody = Data(jsonDictionary: requestDictionary)
let task = session.dataTask(with: request, completionHandler: { (data, response, error) in
var serverError: FileProviderDropboxError?
var jobId: String?
@@ -438,7 +438,7 @@ extension DropboxFileProvider {
if let response = response as? HTTPURLResponse {
let code = FileProviderHTTPErrorCode(rawValue: response.statusCode)
serverError = code != nil ? FileProviderDropboxError(code: code!, path: toPath, errorDescription: String(data: data ?? Data(), encoding: .utf8)) : nil
if let data = data, let jsonStr = String(data: data, encoding: .utf8), let json = jsonToDictionary(jsonStr) {
if let json = data?.deserializeJSON() {
jobId = json["async_job_id"] as? String
if let attribDic = json["metadata"] as? [String: AnyObject] {
fileObject = DropboxFileObject(json: attribDic)
@@ -465,7 +465,7 @@ extension DropboxFileProvider {
request.setValue("Bearer \(credential?.password ?? "")", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let requestDictionary: [String: AnyObject] = ["path": correctPath(toPath)! as NSString, "copy_reference" : reference as NSString]
request.httpBody = dictionaryToJSON(requestDictionary)?.data(using: .utf8)
request.httpBody = Data(jsonDictionary: requestDictionary)
let task = session.dataTask(with: request, completionHandler: { (data, response, error) in
var serverError: FileProviderDropboxError?
if let response = response as? HTTPURLResponse {
@@ -530,17 +530,17 @@ extension DropboxFileProvider: ExtendedFileProvider {
if let dimension = dimension {
requestDictionary["size"] = "w\(Int(dimension.width))h\(Int(dimension.height))" as NSString
}
request.setValue(dictionaryToJSON(requestDictionary), forHTTPHeaderField: "Dropbox-API-Arg")
request.setValue(String(jsonDictionary: requestDictionary), forHTTPHeaderField: "Dropbox-API-Arg")
let task = self.session.dataTask(with: request, completionHandler: { (data, response, error) in
var image: ImageClass? = nil
if let r = response as? HTTPURLResponse, let result = r.allHeaderFields["Dropbox-API-Result"] as? String, let jsonResult = jsonToDictionary(result) {
if let r = response as? HTTPURLResponse, let result = r.allHeaderFields["Dropbox-API-Result"] as? String, let jsonResult = result.deserializeJSON() {
if jsonResult["error"] != nil {
completionHandler(nil, self.throwError(path, code: URLError.cannotDecodeRawData as FoundationErrorEnum))
}
}
if let data = data {
if DropboxFileProvider.dataIsPDF(data) {
image = DropboxFileProvider.convertToImage(pdfData: data)
if data.isPDF, let pageImage = DropboxFileProvider.convertToImage(pdfData: data) {
image = pageImage
} else if let contentType = (response as? HTTPURLResponse)?.allHeaderFields["Content-Type"] as? String, contentType.contains("text/html") {
// TODO: Implement converting html returned type of get_preview to image
} else {
@@ -559,7 +559,7 @@ extension DropboxFileProvider: ExtendedFileProvider {
request.setValue("Bearer \(credential?.password ?? "")", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let requestDictionary: [String: AnyObject] = ["path": correctPath(path)! as NSString, "include_media_info": NSNumber(value: true)]
request.httpBody = dictionaryToJSON(requestDictionary)?.data(using: .utf8)
request.httpBody = Data(jsonDictionary: requestDictionary)
let task = session.dataTask(with: request, completionHandler: { (data, response, error) in
var serverError: FileProviderDropboxError?
var dic = [String: Any]()
@@ -567,7 +567,7 @@ extension DropboxFileProvider: ExtendedFileProvider {
if let response = response as? HTTPURLResponse {
let code = FileProviderHTTPErrorCode(rawValue: response.statusCode)
serverError = code != nil ? FileProviderDropboxError(code: code!, path: path, errorDescription: String(data: data ?? Data(), encoding: .utf8)) : nil
if let data = data, let jsonStr = String(data: data, encoding: .utf8), let json = jsonToDictionary(jsonStr), let properties = json["media_info"] as? [String: Any] {
if let json = data?.deserializeJSON(), let properties = json["media_info"] as? [String: Any] {
(dic, keys) = self.mapMediaInfo(properties)
}
}
+14 -16
View File
@@ -22,7 +22,7 @@ public final class DropboxFileObject: FileObject {
}
internal convenience init? (jsonStr: String) {
guard let json = jsonToDictionary(jsonStr) else { return nil }
guard let json = jsonStr.deserializeJSON() else { return nil }
self.init(json: json)
}
@@ -90,24 +90,23 @@ internal extension DropboxFileProvider {
request.httpMethod = "POST"
request.setValue("Bearer \(credential?.password ?? "")", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = dictionaryToJSON(requestDictionary)?.data(using: .utf8)
request.httpBody = Data(jsonDictionary: requestDictionary)
let task = (session ?? self.session).dataTask(with: request, completionHandler: { (data, response, error) in
var responseError: FileProviderDropboxError?
var files = [DropboxFileObject]()
if let code = (response as? HTTPURLResponse)?.statusCode , code >= 300, let rCode = FileProviderHTTPErrorCode(rawValue: code) {
responseError = FileProviderDropboxError(code: rCode, path: path, errorDescription: String(data: data ?? Data(), encoding: .utf8))
}
if let data = data, let jsonStr = String(data: data, encoding: .utf8) {
let json = jsonToDictionary(jsonStr)
if let entries = json?["entries"] as? [AnyObject] , entries.count > 0 {
if let json = data?.deserializeJSON() {
if let entries = json["entries"] as? [AnyObject] , entries.count > 0 {
files.reserveCapacity(entries.count)
for entry in entries {
if let entry = entry as? [String: AnyObject], let file = DropboxFileObject(json: entry) {
files.append(file)
}
}
let ncursor = json?["cursor"] as? String
let hasmore = (json?["has_more"] as? NSNumber)?.boolValue ?? false
let ncursor = json["cursor"] as? String
let hasmore = (json["has_more"] as? NSNumber)?.boolValue ?? false
if hasmore {
progressHandler?(files, ncursor, responseError ?? error)
self.list(path, cursor: ncursor, prevContents: prevContents + files, completionHandler: completionHandler)
@@ -139,7 +138,7 @@ internal extension DropboxFileProvider {
request.httpMethod = "POST"
request.setValue("Bearer \(credential?.password ?? "")", forHTTPHeaderField: "Authorization")
request.setValue("application/octet-stream", forHTTPHeaderField: "Content-Type")
request.setValue(dictionaryToJSON(requestDictionary), forHTTPHeaderField: "Dropbox-API-Arg")
request.setValue(String(jsonDictionary: requestDictionary), forHTTPHeaderField: "Dropbox-API-Arg")
request.httpBody = data
let task = session.uploadTask(with: request, from: data, completionHandler: { (data, response, error) in
var responseError: FileProviderDropboxError?
@@ -172,7 +171,7 @@ internal extension DropboxFileProvider {
request.httpMethod = "POST"
request.setValue("Bearer \(credential?.password ?? "")", forHTTPHeaderField: "Authorization")
request.setValue("application/octet-stream", forHTTPHeaderField: "Content-Type")
request.setValue(dictionaryToJSON(requestDictionary), forHTTPHeaderField: "Dropbox-API-Arg")
request.setValue(String(jsonDictionary: requestDictionary), forHTTPHeaderField: "Dropbox-API-Arg")
let task = session.uploadTask(with: request, fromFile: localFile, completionHandler: { (data, response, error) in
var responseError: FileProviderDropboxError?
if let code = (response as? HTTPURLResponse)?.statusCode , code >= 300, let rCode = FileProviderHTTPErrorCode(rawValue: code) {
@@ -196,22 +195,21 @@ internal extension DropboxFileProvider {
requestDictionary["query"] = query as NSString
requestDictionary["start"] = start as NSNumber
requestDictionary["max_results"] = maxResultPerPage as NSNumber
request.httpBody = dictionaryToJSON(requestDictionary)?.data(using: .utf8)
request.httpBody = Data(jsonDictionary: requestDictionary)
let task = session.dataTask(with: request, completionHandler: { (data, response, error) in
var responseError: FileProviderDropboxError?
if let code = (response as? HTTPURLResponse)?.statusCode , code >= 300, let rCode = FileProviderHTTPErrorCode(rawValue: code) {
responseError = FileProviderDropboxError(code: rCode, path: startPath, errorDescription: String(data: data ?? Data(), encoding: .utf8))
}
if let data = data, let jsonStr = String(data: data, encoding: .utf8) {
let json = jsonToDictionary(jsonStr)
if let entries = json?["matches"] as? [AnyObject] , entries.count > 0 {
if let json = data?.deserializeJSON() {
if let entries = json["matches"] as? [AnyObject] , entries.count > 0 {
for entry in entries {
if let entry = entry as? [String: AnyObject], let file = DropboxFileObject(json: entry) {
foundItem(file)
}
}
let rstart = json?["start"] as? Int
let hasmore = (json?["more"] as? NSNumber)?.boolValue ?? false
let rstart = json["start"] as? Int
let hasmore = (json["more"] as? NSNumber)?.boolValue ?? false
if hasmore, let rstart = rstart {
self.search(startPath, query: query, start: rstart + entries.count, maxResultPerPage: maxResultPerPage, foundItem: foundItem, completionHandler: completionHandler)
} else {
@@ -254,7 +252,7 @@ internal extension DropboxFileProvider {
}
if let duration = json["duration"] as? UInt64 {
keys.append("Duration")
dic["Duration"] = DropboxFileProvider.formatshort(interval: TimeInterval(duration))
dic["Duration"] = TimeInterval(duration).formatshort
}
return (dic, keys)
}
+22 -35
View File
@@ -225,8 +225,7 @@ public struct LocalFileInformationGenerator {
/// Thumbnail generator closure for portable document files files.
static public var pdfThumbnail: (_ fileURL: URL) -> ImageClass? = { fileURL in
guard let data = try? Data(contentsOf: fileURL) else { return nil }
return LocalFileProvider.convertToImage(pdfData: data)
return LocalFileProvider.convertToImage(pdfURL: fileURL)
}
/// Thumbnail generator closure for office document files.
@@ -247,7 +246,7 @@ public struct LocalFileInformationGenerator {
var keys = [String]()
func add(key: String, value: Any?) {
if let value = value {
if let value = value, !((value as? String)?.isEmpty ?? false) {
keys.append(key)
dic[key] = value
}
@@ -282,26 +281,25 @@ public struct LocalFileInformationGenerator {
add(key: "Device model", value: tiffDict[kCGImagePropertyTIFFModel as String])
add(key: "Lens model", value: exifDict[kCGImagePropertyExifLensModel as String])
add(key: "Artist", value: tiffDict[kCGImagePropertyTIFFArtist as String] as? String)
if let cr = tiffDict[kCGImagePropertyTIFFCopyright as String] as? String , !cr.isEmpty {
add(key: "Copyright", value: cr)
}
if let date = tiffDict[kCGImagePropertyTIFFDateTime as String] as? String , !date.isEmpty {
add(key: "Date taken", value: date)
}
add(key: "Copyright", value: tiffDict[kCGImagePropertyTIFFCopyright as String] as? String)
add(key: "Date taken", value: tiffDict[kCGImagePropertyTIFFDateTime as String] as? String)
if let latitude = tiffDict[kCGImagePropertyGPSLatitude as String] as? NSNumber, let longitude = tiffDict[kCGImagePropertyGPSLongitude as String] as? NSNumber {
add(key: "Location", value: "\(latitude), \(longitude)")
}
add(key: "Altitude", value: tiffDict[kCGImagePropertyGPSAltitude as String] as? NSNumber)
add(key: "Area", value: tiffDict[kCGImagePropertyGPSAreaInformation as String])
add(key: "Color space", value: imageDict[kCGImagePropertyColorModel as String])
add(key: "Focal length", value: exifDict[kCGImagePropertyExifFocalLength as String])
add(key: "F number", value: exifDict[kCGImagePropertyExifFNumber as String])
add(key: "Exposure program", value: exifDict[kCGImagePropertyExifExposureProgram as String])
if let exp = exifDict[kCGImagePropertyExifExposureTime as String] as? NSNumber {
let expfrac = simplify(Int64(exp.doubleValue * 10_000_000_000_000), 10_000_000_000_000)
let expfrac = simplify(Int64(exp.doubleValue * 1_163_962_800_000), 1_163_962_800_000)
add(key: "Exposure time", value: "\(expfrac.newTop)/\(expfrac.newBottom)")
}
add(key: "ISO speed", value: (exifDict[kCGImagePropertyExifISOSpeedRatings as String] as? NSArray)?.first)
add(key: "ISO speed", value: (exifDict[kCGImagePropertyExifISOSpeedRatings as String] as? [NSNumber])?.first)
return (dic, keys)
}
@@ -340,7 +338,7 @@ public struct LocalFileInformationGenerator {
}
}
if let ap = try? AVAudioPlayer(contentsOf: fileURL) {
add(key: "Duration", value: LocalFileProvider.formatshort(interval: ap.duration))
add(key: "Duration", value: ap.duration.formatshort)
add(key: "Bitrate", value: ap.settings[AVSampleRateKey] as? Int)
}
}
@@ -379,7 +377,7 @@ public struct LocalFileInformationGenerator {
duration += track.timeRange.duration.timescale > 0 ? track.timeRange.duration.value / Int64(track.timeRange.duration.timescale) : 0
bitrate += track.estimatedDataRate
}
add(key: "Duration", value: LocalFileProvider.formatshort(interval: TimeInterval(duration)))
add(key: "Duration", value: TimeInterval(duration).formatshort)
add(key: "Video Bitrate", value: "\(Int(ceil(bitrate / 1000))) kbps")
}
let audioTracks = asset.tracks(withMediaType: AVMediaTypeAudio)
@@ -398,7 +396,7 @@ public struct LocalFileInformationGenerator {
var keys = [String]()
func add(key: String, value: Any?) {
if let value = value {
if let value = value, !((value as? String)?.isEmpty ?? false) {
keys.append(key)
dic[key] = value
}
@@ -412,7 +410,8 @@ public struct LocalFileInformationGenerator {
return nil
}
func convertDate(_ date: String) -> Date? {
func convertDate(_ date: String?) -> Date? {
guard let date = date else { return nil }
var dateStr = date
if dateStr.hasPrefix("D:") {
dateStr = date.substring(from: date.characters.index(date.startIndex, offsetBy: 2))
@@ -429,16 +428,10 @@ public struct LocalFileInformationGenerator {
return nil
}
if let data = try? Data(contentsOf: fileURL), let provider = CGDataProvider(data: data as CFData), let reference = CGPDFDocument(provider), let dict = reference.info {
if let title = getKey("Title", from: dict), !title.isEmpty {
add(key: "Title", value: title)
}
if let author = getKey("Author", from: dict), !author.isEmpty {
add(key: "Author", value: author)
}
if let subject = getKey("Subject", from: dict), !subject.isEmpty {
add(key: "Subject", value: subject)
}
if let provider = CGDataProvider(url: fileURL as CFURL), let reference = CGPDFDocument(provider), let dict = reference.info {
add(key: "Title", value: getKey("Title", from: dict))
add(key: "Author", value: getKey("Author", from: dict))
add(key: "Subject", value: getKey("Subject", from: dict))
var majorVersion: Int32 = 0
var minorVersion: Int32 = 0
reference.getVersion(majorVersion: &majorVersion, minorVersion: &minorVersion)
@@ -451,15 +444,9 @@ public struct LocalFileInformationGenerator {
let size = pageRef.getBoxRect(CGPDFBox.mediaBox).size
add(key: "Resolution", value: "\(Int(size.width))x\(Int(size.height))")
}
if let creator = getKey("Creator", from: dict), !creator.isEmpty {
add(key: "Content creator", value: creator)
}
if let creationDateString = getKey("CreationDate", from: dict) {
add(key: "Creation date", value: convertDate(creationDateString))
}
if let modifiedDateString = getKey("ModDate", from: dict) {
add(key: "Modified date", value: convertDate(modifiedDateString))
}
add(key: "Content creator", value: getKey("Creator", from: dict))
add(key: "Creation date", value: convertDate(getKey("CreationDate", from: dict)))
add(key: "Modified date", value: convertDate(getKey("ModDate", from: dict)))
add(key: "Security", value: reference.isEncrypted ? "Present" : "None")
add(key: "Allows printing", value: reference.allowsPrinting ? "Yes" : "No")
add(key: "Allows copying", value: reference.allowsCopying ? "Yes" : "No")
+4 -4
View File
@@ -239,10 +239,10 @@ internal class FPSStreamTask: URLSessionTask, StreamDelegate {
var timedOut: Bool = false
dispatch_queue.async {
if timeout > 0 {
self.dispatch_queue.asyncAfter(deadline: DispatchTime.now() + Double(Int64(timeout * 1_000_000_000)) / Double(NSEC_PER_SEC), execute: {
self.dispatch_queue.asyncAfter(deadline: .now() + 1) {
timedOut = true
completionHandler(nil, inputStream.streamStatus == .atEnd, inputStream.streamError as NSError?)
})
}
}
while (self.dataReceived.length == 0 || self.dataReceived.length < minBytes) && !timedOut {
RunLoop.current.run(until: Date(timeIntervalSinceNow: 0.1));
@@ -277,10 +277,10 @@ internal class FPSStreamTask: URLSessionTask, StreamDelegate {
var timedOut: Bool = false
dispatch_queue.async {
if timeout > 0 {
self.dispatch_queue.asyncAfter(deadline: DispatchTime.now() + Double(Int64(timeout * 1_000_000_000)) / Double(NSEC_PER_SEC), execute: {
self.dispatch_queue.asyncAfter(deadline: .now() + 1) {
timedOut = true
completionHandler(self._error)
})
}
}
self.dataToBeSent.append(data)
-59
View File
@@ -321,62 +321,3 @@ public struct FileObjectSorting {
}
}
}
extension Array where Element: FileObject {
/// Returns a sorted array of `FileObject`s by criterias set in attributes.
public func sort(by type: FileObjectSorting.SortType, ascending: Bool = true, isDirectoriesFirst: Bool = false) -> [Element] {
let sorting = FileObjectSorting(type: type, ascending: ascending, isDirectoriesFirst: isDirectoriesFirst)
return sorting.sort(self) as! [Element]
}
/// Sorts array of `FileObject`s by criterias set in attributes.
public mutating func sorted(by type: FileObjectSorting.SortType, ascending: Bool = true, isDirectoriesFirst: Bool = false) {
self = self.sort(by: type, ascending: ascending, isDirectoriesFirst: isDirectoriesFirst)
}
}
extension URLFileResourceType {
/// Returns corresponding `URLFileResourceType` of a `FileAttributeType` value
public init(fileTypeValue: FileAttributeType) {
switch fileTypeValue {
case FileAttributeType.typeCharacterSpecial: self = .characterSpecial
case FileAttributeType.typeDirectory: self = .directory
case FileAttributeType.typeBlockSpecial: self = .blockSpecial
case FileAttributeType.typeRegular: self = .regular
case FileAttributeType.typeSymbolicLink: self = .symbolicLink
case FileAttributeType.typeSocket: self = .socket
case FileAttributeType.typeUnknown: self = .unknown
default: self = .unknown
}
}
}
internal extension URLResourceKey {
static let fileURL = URLResourceKey(rawValue: "NSURLFileURLKey")
static let serverDate = URLResourceKey(rawValue: "NSURLServerDateKey")
static let entryTag = URLResourceKey(rawValue: "NSURLEntryTagKey")
static let mimeType = URLResourceKey(rawValue: "NSURLMIMETypeIdentifierKey")
}
internal extension URL {
var uw_scheme: String {
return self.scheme ?? ""
}
}
internal func jsonToDictionary(_ jsonString: String) -> [String: AnyObject]? {
guard let data = jsonString.data(using: .utf8) else {
return nil
}
if let dic = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions()) as? [String: AnyObject] {
return dic
}
return nil
}
internal func dictionaryToJSON(_ dictionary: [String: AnyObject]) -> String? {
if let data = try? JSONSerialization.data(withJSONObject: dictionary, options: JSONSerialization.WritingOptions()) {
return String(data: data, encoding: .utf8)
}
return nil
}
+104 -116
View File
@@ -95,7 +95,7 @@ public protocol FileProviderBasic: class {
- Parameters:
- path: location of directory to start search
- recursive: Searching subdirectories of path
- query: Simple string that file name contains to be search, case-insensitive.
- query: Simple string that file name begins with to be search, case-insensitive.
- foundItemHandler: Closure which is called when a file is found
- completionHandler: Closure which will be called after finishing search. Returns an arry of `FileObject` or error if occured.
*/
@@ -138,7 +138,7 @@ public protocol FileProviderBasic: class {
extension FileProviderBasic {
public func searchFiles(path: String, recursive: Bool, query: String, foundItemHandler: ((FileObject) -> Void)?, completionHandler: @escaping ((_ files: [FileObject], _ error: Error?) -> Void)) {
let predicate = NSPredicate(format: "name CONTAINS[c] %@", query)
let predicate = NSPredicate(format: "name BEGINSWITH[c] %@", query)
self.searchFiles(path: path, recursive: recursive, query: predicate, foundItemHandler: foundItemHandler, completionHandler: completionHandler)
}
@@ -170,7 +170,7 @@ public func ==(lhs: FileProviderBasic, rhs: FileProviderBasic) -> Bool {
return lhs.type == rhs.type && lhs.baseURL == rhs.baseURL && lhs.credential == rhs.credential
}
/// Cancels all active underlying tasks
/// Cancels all active underlying tasks when deallocating remote providers
public var fileProviderCancelTasksOnInvalidating = true
/// Extending `FileProviderBasic` for web-based file providers
@@ -220,7 +220,7 @@ internal extension FileProviderBasicRemote {
}
group.leave()
}).resume()
_ = group.wait(timeout: DispatchTime.now() + self.session.configuration.timeoutIntervalForRequest)
_ = group.wait(timeout: .now() + self.session.configuration.timeoutIntervalForRequest)
}
if validatedCache {
completionHandler(response.data, response.response, nil)
@@ -637,15 +637,17 @@ extension FileProviderBasic {
/// - Returns: A `String` contains relative path of url against base url.
public func relativePathOf(url: URL) -> String {
// check if url derieved from current base url
if !url.relativePath.isEmpty, url.baseURL == self.baseURL {
return url.relativePath.removingPercentEncoding!
let relativePath = url.relativePath
if !relativePath.isEmpty, url.baseURL == self.baseURL {
return relativePath.removingPercentEncoding ?? relativePath
}
// resolve url string against baseurl
guard let baseURL = self.baseURL?.standardizedFileURL else { return url.absoluteString }
let standardPath = url.absoluteString.replacingOccurrences(of: "file:///private/var/", with: "file:///var/", options: .anchored)
let standardBase = baseURL.absoluteString.replacingOccurrences(of: "file:///private/var/", with: "file:///var/", options: .anchored)
return standardPath.replacingOccurrences(of: standardBase, with: "/").removingPercentEncoding!
let standardRelativePath = standardPath.replacingOccurrences(of: standardBase, with: "/")
return standardRelativePath.removingPercentEncoding ?? standardRelativePath
}
internal func correctPath(_ path: String?) -> String? {
@@ -690,7 +692,7 @@ extension FileProviderBasic {
}
group.leave()
}
_ = group.wait(timeout: DispatchTime.now() + 5)
_ = group.wait(timeout: .now() + 5)
let finalFile = result + (!fileExt.isEmpty ? "." + fileExt : "")
return (dirPath as NSString).appendingPathComponent(finalFile)
}
@@ -777,96 +779,82 @@ extension ExtendedFileProvider {
self.thumbnailOfFile(path: path, dimension: nil, completionHandler: completionHandler)
}
internal static func formatshort(interval: TimeInterval) -> String {
var result = "0:00"
if interval < TimeInterval(Int32.max) {
result = ""
var time = DateComponents()
time.hour = Int(interval / 3600)
time.minute = Int((interval.truncatingRemainder(dividingBy: 3600)) / 60)
time.second = Int(interval.truncatingRemainder(dividingBy: 60))
let formatter = NumberFormatter()
formatter.paddingCharacter = "0"
formatter.minimumIntegerDigits = 2
formatter.maximumFractionDigits = 0
let formatterFirst = NumberFormatter()
formatterFirst.maximumFractionDigits = 0
if time.hour! > 0 {
result = "\(formatterFirst.string(from: NSNumber(value: time.hour!))!):\(formatter.string(from: NSNumber(value: time.minute!))!):\(formatter.string(from: NSNumber(value: time.second!))!)"
} else {
result = "\(formatterFirst.string(from: NSNumber(value: time.minute!))!):\(formatter.string(from: NSNumber(value: time.second!))!)"
}
}
result = result.trimmingCharacters(in: CharacterSet(charactersIn: ": "))
return result
}
internal static func dataIsPDF(_ data: Data) -> Bool {
return data.count > 4 && data.scanString(length: 4, encoding: .ascii) == "%PDF"
}
internal static func convertToImage(pdfData: Data?, page: Int = 1) -> ImageClass? {
guard let pdfData = pdfData else { return nil }
let cfPDFData: CFData = pdfData as CFData
if let provider = CGDataProvider(data: cfPDFData), let reference = CGPDFDocument(provider), let pageRef = reference.page(at: page) {
let frame = pageRef.getBoxRect(CGPDFBox.mediaBox)
var size = frame.size
let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
#if os(macOS)
let ppp = Int(NSScreen.main()?.backingScaleFactor ?? 1) // fetch device is retina or not
size.width *= CGFloat(ppp)
size.height *= CGFloat(ppp)
let rep = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: Int(size.width), pixelsHigh: Int(size.height),
bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: NSCalibratedRGBColorSpace,
bytesPerRow: 0, bitsPerPixel: 0)
guard let context = NSGraphicsContext(bitmapImageRep: rep!) else {
return nil
}
NSGraphicsContext.saveGraphicsState()
NSGraphicsContext.setCurrent(context)
let transform = pageRef.getDrawingTransform(CGPDFBox.mediaBox, rect: rect, rotate: 0, preserveAspectRatio: true)
context.cgContext.concatenate(transform)
context.cgContext.translateBy(x: 0, y: size.height)
context.cgContext.scaleBy(x: CGFloat(ppp), y: CGFloat(-ppp))
context.cgContext.drawPDFPage(pageRef)
let resultingImage = NSImage(size: size)
resultingImage.addRepresentation(rep!)
return resultingImage
#else
let ppp = Int(UIScreen.main.scale) // fetch device is retina or not
guard let context = UIGraphicsGetCurrentContext() else {
return nil
}
size.width *= CGFloat(ppp)
size.height *= CGFloat(ppp)
UIGraphicsBeginImageContext(size)
context.saveGState()
let transform = pageRef.getDrawingTransform(CGPDFBox.mediaBox, rect: rect, rotate: 0, preserveAspectRatio: true)
context.concatenate(transform)
context.translateBy(x: 0, y: size.height)
context.scaleBy(x: CGFloat(ppp), y: CGFloat(-ppp))
context.drawPDFPage(pageRef)
context.restoreGState()
let resultingImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return resultingImage
#endif
return self.convertToImage(pdfPage: pageRef)
}
return nil
}
internal static func convertToImage(pdfURL: URL, page: Int = 1) -> ImageClass? {
// To accelerate, supporting only local file URL
guard pdfURL.isFileURL else { return nil }
if let reference = CGPDFDocument(pdfURL as CFURL), let pageRef = reference.page(at: page) {
return self.convertToImage(pdfPage: pageRef)
}
return nil
}
private static func convertToImage(pdfPage: CGPDFPage) -> ImageClass? {
let frame = pdfPage.getBoxRect(CGPDFBox.mediaBox)
var size = frame.size
let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
#if os(macOS)
let ppp = Int(NSScreen.main()?.backingScaleFactor ?? 1) // fetch device is retina or not
size.width *= CGFloat(ppp)
size.height *= CGFloat(ppp)
let rep = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: Int(size.width), pixelsHigh: Int(size.height),
bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: NSCalibratedRGBColorSpace,
bytesPerRow: 0, bitsPerPixel: 0)
guard let context = NSGraphicsContext(bitmapImageRep: rep!) else {
return nil
}
NSGraphicsContext.saveGraphicsState()
NSGraphicsContext.setCurrent(context)
let transform = pdfPage.getDrawingTransform(CGPDFBox.mediaBox, rect: rect, rotate: 0, preserveAspectRatio: true)
context.cgContext.concatenate(transform)
context.cgContext.translateBy(x: 0, y: size.height)
context.cgContext.scaleBy(x: CGFloat(ppp), y: CGFloat(-ppp))
context.cgContext.drawPDFPage(pdfPage)
let resultingImage = NSImage(size: size)
resultingImage.addRepresentation(rep!)
return resultingImage
#else
let ppp = Int(UIScreen.main.scale) // fetch device is retina or not
guard let context = UIGraphicsGetCurrentContext() else {
return nil
}
size.width *= CGFloat(ppp)
size.height *= CGFloat(ppp)
UIGraphicsBeginImageContext(size)
context.saveGState()
let transform = pdfPage.getDrawingTransform(CGPDFBox.mediaBox, rect: rect, rotate: 0, preserveAspectRatio: true)
context.concatenate(transform)
context.translateBy(x: 0, y: size.height)
context.scaleBy(x: CGFloat(ppp), y: CGFloat(-ppp))
context.drawPDFPage(pdfPage)
context.restoreGState()
let resultingImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return resultingImage
#endif
}
internal static func scaleDown(image: ImageClass, toSize maxSize: CGSize) -> ImageClass {
let height, width: CGFloat
if image.size.width > image.size.height {
@@ -948,11 +936,37 @@ public enum FileOperationType: CustomStringConvertible {
return mirror.children.dropFirst().first?.value as? String
}
init? (json: [String: AnyObject]) {
guard let type = json["type"] as? String, let source = json["source"] as? String else {
return nil
}
let dest = json["dest"] as? String
switch type {
case "Create":
self = .create(path: source)
case "Modify":
self = .modify(path: source)
case "Remove":
self = .remove(path: source)
case "Copy":
guard let dest = dest else { return nil }
self = .copy(source: source, destination: dest)
case "Move":
guard let dest = dest else { return nil }
self = .move(source: source, destination: dest)
case "Link":
guard let dest = dest else { return nil }
self = .link(link: source, target: dest)
default:
return nil
}
}
internal var json: String? {
var dictionary: [String: AnyObject] = ["type": self.description as NSString]
dictionary["source"] = source as NSString?
dictionary["dest"] = destination as NSString?
return dictionaryToJSON(dictionary)
return String(jsonDictionary: dictionary)
}
}
@@ -1024,29 +1038,3 @@ public protocol FoundationErrorEnum {
var rawValue: Int { get }
}
extension NSPredicate {
func findValue(forKey key: String?, operator op: NSComparisonPredicate.Operator? = nil) -> Any? {
let val = findAllValues(forKey: key).lazy.filter { op == nil || $0.operator == op! }
return val.first?.value
}
func findAllValues(forKey key: String?) -> [(value: Any, operator: NSComparisonPredicate.Operator)] {
if let cQuery = self as? NSCompoundPredicate {
let find = cQuery.subpredicates.flatMap { ($0 as! NSPredicate).findAllValues(forKey: key) }
return find
} else if let cQuery = self as? NSComparisonPredicate {
if cQuery.leftExpression.expressionType == .keyPath, key == nil || cQuery.leftExpression.keyPath == key!, let const = cQuery.rightExpression.constantValue {
return [(value: const, operator: cQuery.predicateOperatorType)]
}
if cQuery.rightExpression.expressionType == .keyPath, key == nil || cQuery.rightExpression.keyPath == key!, let const = cQuery.leftExpression.constantValue {
return [(value: const, operator: cQuery.predicateOperatorType)]
}
return []
} else {
return []
}
}
}
extension URLError.Code: FoundationErrorEnum {}
extension CocoaError.Code: FoundationErrorEnum {}
+182
View File
@@ -0,0 +1,182 @@
//
// FileProviderExtensions.swift
// FileProvider
//
// Created by Amir Abbas on 12/27/1395 AP.
//
//
import Foundation
extension Array where Element: FileObject {
/// Returns a sorted array of `FileObject`s by criterias set in attributes.
public func sort(by type: FileObjectSorting.SortType, ascending: Bool = true, isDirectoriesFirst: Bool = false) -> [Element] {
let sorting = FileObjectSorting(type: type, ascending: ascending, isDirectoriesFirst: isDirectoriesFirst)
return sorting.sort(self) as! [Element]
}
/// Sorts array of `FileObject`s by criterias set in attributes.
public mutating func sorted(by type: FileObjectSorting.SortType, ascending: Bool = true, isDirectoriesFirst: Bool = false) {
self = self.sort(by: type, ascending: ascending, isDirectoriesFirst: isDirectoriesFirst)
}
}
extension URLFileResourceType {
/// Returns corresponding `URLFileResourceType` of a `FileAttributeType` value
public init(fileTypeValue: FileAttributeType) {
switch fileTypeValue {
case FileAttributeType.typeCharacterSpecial: self = .characterSpecial
case FileAttributeType.typeDirectory: self = .directory
case FileAttributeType.typeBlockSpecial: self = .blockSpecial
case FileAttributeType.typeRegular: self = .regular
case FileAttributeType.typeSymbolicLink: self = .symbolicLink
case FileAttributeType.typeSocket: self = .socket
case FileAttributeType.typeUnknown: self = .unknown
default: self = .unknown
}
}
}
internal extension URLResourceKey {
static let fileURL = URLResourceKey(rawValue: "NSURLFileURLKey")
static let serverDate = URLResourceKey(rawValue: "NSURLServerDateKey")
static let entryTag = URLResourceKey(rawValue: "NSURLEntryTagKey")
static let mimeType = URLResourceKey(rawValue: "NSURLMIMETypeIdentifierKey")
}
internal extension URL {
var uw_scheme: String {
return self.scheme ?? ""
}
var fileIsDirectory: Bool {
return (try? self.resourceValues(forKeys: [.isDirectoryKey]))?.isDirectory ?? false
}
var fileSize: Int64 {
return Int64((try? self.resourceValues(forKeys: [.fileSizeKey]))?.fileSize ?? -1)
}
var fileExists: Bool {
return self.isFileURL && FileManager.default.fileExists(atPath: self.path)
}
}
internal extension Data {
internal var isPDF: Bool {
return self.count > 4 && self.scanString(length: 4, using: .ascii) == "%PDF"
}
init? (jsonDictionary dictionary: [String: AnyObject]) {
guard let data = try? JSONSerialization.data(withJSONObject: dictionary, options: []) else {
return nil
}
self = data
}
func deserializeJSON() -> [String: AnyObject]? {
if let dic = try? JSONSerialization.jsonObject(with: self, options: []) as? [String: AnyObject] {
return dic
}
return nil
}
init<T>(value: T) {
var value = value
self = Data(buffer: UnsafeBufferPointer(start: &value, count: 1))
}
func scanValue<T>() -> T? {
guard MemoryLayout<T>.size <= self.count else { return nil }
return self.withUnsafeBytes { $0.pointee }
}
func scanValue<T>(start: Int) -> T? {
let length = MemoryLayout<T>.size
guard self.count >= start + length else { return nil }
return self.subdata(in: start..<start+length).withUnsafeBytes { $0.pointee }
}
func scanString(start: Int = 0, length: Int, using encoding: String.Encoding = .utf8) -> String? {
guard self.count >= start + length else { return nil }
return String(data: self.subdata(in: start..<start+length), encoding: encoding)
}
static func mapMemory<T, U>(from: T) -> U? {
guard MemoryLayout<T>.size >= MemoryLayout<U>.size else { return nil }
let data = Data(value: from)
return data.scanValue()
}
}
internal extension String {
init? (jsonDictionary: [String: AnyObject]) {
guard let data = Data(jsonDictionary: jsonDictionary) else {
return nil
}
self.init(data: data, encoding: .utf8)
}
func deserializeJSON(using encoding: String.Encoding = .utf8) -> [String: AnyObject]? {
guard let data = self.data(using: encoding) else {
return nil
}
return data.deserializeJSON()
}
}
internal extension TimeInterval {
internal var formatshort: String {
var result = "0:00"
if self < TimeInterval(Int32.max) {
result = ""
var time = DateComponents()
time.hour = Int(self / 3600)
time.minute = Int((self.truncatingRemainder(dividingBy: 3600)) / 60)
time.second = Int(self.truncatingRemainder(dividingBy: 60))
let formatter = NumberFormatter()
formatter.paddingCharacter = "0"
formatter.minimumIntegerDigits = 2
formatter.maximumFractionDigits = 0
let formatterFirst = NumberFormatter()
formatterFirst.maximumFractionDigits = 0
if time.hour! > 0 {
result = "\(formatterFirst.string(from: NSNumber(value: time.hour!))!):\(formatter.string(from: NSNumber(value: time.minute!))!):\(formatter.string(from: NSNumber(value: time.second!))!)"
} else {
result = "\(formatterFirst.string(from: NSNumber(value: time.minute!))!):\(formatter.string(from: NSNumber(value: time.second!))!)"
}
}
result = result.trimmingCharacters(in: CharacterSet(charactersIn: ": "))
return result
}
}
extension NSPredicate {
func findValue(forKey key: String?, operator op: NSComparisonPredicate.Operator? = nil) -> Any? {
let val = findAllValues(forKey: key).lazy.filter { (op == nil || $0.operator == op!) && !$0.not }
return val.first?.value
}
func findAllValues(forKey key: String?) -> [(value: Any, operator: NSComparisonPredicate.Operator, not: Bool)] {
if let cQuery = self as? NSCompoundPredicate {
let find = cQuery.subpredicates.flatMap { ($0 as! NSPredicate).findAllValues(forKey: key) }
if cQuery.compoundPredicateType == .not {
return find.map { return ($0.value, $0.operator, !$0.not) }
}
return find
} else if let cQuery = self as? NSComparisonPredicate {
if cQuery.leftExpression.expressionType == .keyPath, key == nil || cQuery.leftExpression.keyPath == key!, let const = cQuery.rightExpression.constantValue {
return [(value: const, operator: cQuery.predicateOperatorType, false)]
}
if cQuery.rightExpression.expressionType == .keyPath, key == nil || cQuery.rightExpression.keyPath == key!, let const = cQuery.leftExpression.constantValue {
return [(value: const, operator: cQuery.predicateOperatorType, false)]
}
return []
} else {
return []
}
}
}
extension URLError.Code: FoundationErrorEnum {}
extension CocoaError.Code: FoundationErrorEnum {}
+12 -6
View File
@@ -42,15 +42,21 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor, FileProvideUndo
*/
open var isCoorinating: Bool
/// **OBSOLETED**: Use FileProvider.init(for:in:) instead.
@available(*, obsoleted: 1.0, renamed: "init(for:in:)", message: "Use FileProvider.init(for:in:) instead.")
public convenience init (directory: FileManager.SearchPathDirectory = .documentDirectory, domainMask: FileManager.SearchPathDomainMask = .userDomainMask) {
self.init(baseURL: FileManager.default.urls(for: directory, in: domainMask).first!)
}
/**
Initializes provider for the specified common directory in the requested domains.
default values are `directory: .documentDirectory, domainMask: .userDomainMask`.
- Parameters:
- directory: The search path directory. The supported values are described in `FileManager.SearchPathDirectory`.
- domainMask: The file system domain to search. The value for this parameter is one or more of the constants described in `FileManager.SearchPathDomainMask`.
*/
public convenience init (directory: FileManager.SearchPathDirectory = .documentDirectory, domainMask: FileManager.SearchPathDomainMask = .userDomainMask) {
- for: The search path directory. The supported values are described in `FileManager.SearchPathDirectory`.
- in: Base locations for directory to search. The value for this parameter is one or more of the constants described in `FileManager.SearchPathDomainMask`.
*/
public convenience init (for directory: FileManager.SearchPathDirectory = .documentDirectory, in domainMask: FileManager.SearchPathDomainMask = .userDomainMask) {
self.init(baseURL: FileManager.default.urls(for: directory, in: domainMask).first!)
}
@@ -285,7 +291,7 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor, FileProvideUndo
if sourcePath.hasSuffix("/") {
try self.opFileManager.createDirectory(at: source, withIntermediateDirectories: true, attributes: [:])
} else {
try data?.write(to: source, options: Data.WritingOptions.atomic)
try data?.write(to: source, options: .atomic)
}
case .modify:
try data?.write(to: source, options: atomically ? [.atomic] : [])
@@ -474,7 +480,7 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor, FileProvideUndo
open func registerNotifcation(path: String, eventHandler: @escaping (() -> Void)) {
self.unregisterNotifcation(path: path)
let dirurl = self.url(of: path)
let isdir = (try? dirurl.resourceValues(forKeys: [.isDirectoryKey]).isDirectory ?? false) ?? false
let isdir = (try? dirurl.resourceValues(forKeys: [.isDirectoryKey]))?.isDirectory ?? false
if !isdir {
return
}
+14 -34
View File
@@ -21,15 +21,12 @@ public final class LocalFileObject: FileObject {
if relativeURL != nil && rpath.hasPrefix("/") {
rpath.remove(at: rpath.startIndex)
}
if rpath.isEmpty {
fileURL = relativeURL
if #available(iOS 9.0, macOS 10.11, tvOS 9.0, *) {
fileURL = URL(fileURLWithPath: rpath, relativeTo: relativeURL)
} else {
if #available(iOS 9.0, macOS 10.11, tvOS 9.0, *) {
fileURL = URL(fileURLWithPath: rpath, relativeTo: relativeURL)
} else {
fileURL = URL(string: rpath, relativeTo: relativeURL)
}
fileURL = URL(string: rpath.isEmpty ? "./" : rpath, relativeTo: relativeURL)
}
if let fileURL = fileURL {
self.init(fileWithURL: fileURL)
} else {
@@ -96,7 +93,7 @@ internal final class LocalFolderMonitor {
init(url: URL, handler: @escaping ()->Void) {
self.url = url
descriptor = open((url as NSURL).fileSystemRepresentation, O_EVTONLY)
source = DispatchSource.makeFileSystemObjectSource(fileDescriptor: descriptor, eventMask: DispatchSource.FileSystemEvent.write, queue: qq)
source = DispatchSource.makeFileSystemObjectSource(fileDescriptor: descriptor, eventMask: .write, queue: qq)
// Folder monitoring is recursive and deep. Monitoring a root folder may be very costly
// We have a 0.2 second delay to ensure we wont call handler 1000s times when there is
// a huge file operation. This ensures app will work smoothly while this 250 milisec won't
@@ -108,7 +105,7 @@ internal final class LocalFolderMonitor {
}
self.monitoredTime = Date().timeIntervalSinceReferenceDate
self.source.suspend()
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.25, execute: {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.25, execute: {
handler()
self.source.resume()
})
@@ -299,18 +296,15 @@ open class LocalOperationHandle: OperationHandle {
let fp = FileManager()
let filesList = fp.enumerator(at: pathURL, includingPropertiesForKeys: keys, options: enumOpt, errorHandler: nil)
while let fileURL = filesList?.nextObject() as? URL {
do {
let values = try fileURL.resourceValues(forKeys: [.isDirectoryKey, .fileSizeKey])
let isdir = values.isDirectory ?? false
let size = Int64(values.fileSize ?? 0)
if isdir {
folders += 1
} else {
files += 1
}
totalsize += size
} catch _ {
guard let values = try? fileURL.resourceValues(forKeys: [.isDirectoryKey, .fileSizeKey]) else { continue }
let isdir = values.isDirectory ?? false
let size = Int64(values.fileSize ?? 0)
if isdir {
folders += 1
} else {
files += 1
}
totalsize += size
}
return (folders, files, totalsize)
@@ -329,17 +323,3 @@ class UndoBox: NSObject {
self.undoOperation = undoOperation
}
}
internal extension URL {
var fileIsDirectory: Bool {
return (try? self.resourceValues(forKeys: [.isDirectoryKey]))?.isDirectory ?? false
}
var fileSize: Int64 {
return Int64((try? self.resourceValues(forKeys: [.fileSizeKey]))?.fileSize ?? -1)
}
var fileExists: Bool {
return self.isFileURL && FileManager.default.fileExists(atPath: self.path)
}
}
+6 -6
View File
@@ -105,7 +105,7 @@ open class OneDriveFileProvider: FileProviderBasicRemote {
if let response = response as? HTTPURLResponse {
let code = FileProviderHTTPErrorCode(rawValue: response.statusCode)
serverError = code != nil ? FileProviderOneDriveError(code: code!, path: path, errorDescription: String(data: data ?? Data(), encoding: .utf8)) : nil
if let data = data, let jsonStr = String(data: data, encoding: .utf8), let json = jsonToDictionary(jsonStr), let file = OneDriveFileObject(baseURL: self.baseURL, drive: self.drive, json: json) {
if let json = data?.deserializeJSON(), let file = OneDriveFileObject(baseURL: self.baseURL, drive: self.drive, json: json) {
fileObject = file
}
}
@@ -121,7 +121,7 @@ open class OneDriveFileProvider: FileProviderBasicRemote {
let task = session.dataTask(with: request, completionHandler: { (data, response, error) in
var totalSize: Int64 = -1
var usedSize: Int64 = 0
if let data = data, let jsonStr = String(data: data, encoding: .utf8), let json = jsonToDictionary(jsonStr) {
if let json = data?.deserializeJSON() {
totalSize = (json["total"] as? NSNumber)?.int64Value ?? -1
usedSize = (json["used"] as? NSNumber)?.int64Value ?? 0
}
@@ -236,7 +236,7 @@ extension OneDriveFileProvider: FileProviderOperations {
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
requestDictionary["parentReference"] = ("/drive/\(drive):" + dest.deletingLastPathComponent) as NSString
requestDictionary["name"] = dest.lastPathComponent as NSString
request.httpBody = dictionaryToJSON(requestDictionary)?.data(using: .utf8)
request.httpBody = Data(jsonDictionary: requestDictionary)
}
let task = session.dataTask(with: request, completionHandler: { (data, response, error) in
var serverError: FileProviderOneDriveError?
@@ -356,14 +356,14 @@ extension OneDriveFileProvider: FileProviderReadWrite {
var request = URLRequest(url: self.url(of: path, modifier: "action.createLink"))
request.httpMethod = "POST"
let requestDictionary: [String: AnyObject] = ["type": "view" as NSString]
request.httpBody = dictionaryToJSON(requestDictionary)?.data(using: .utf8)
request.httpBody = Data(jsonDictionary: requestDictionary)
let task = session.dataTask(with: request, completionHandler: { (data, response, error) in
var serverError: FileProviderOneDriveError?
var link: URL?
if let response = response as? HTTPURLResponse {
let code = FileProviderHTTPErrorCode(rawValue: response.statusCode)
serverError = code != nil ? FileProviderOneDriveError(code: code!, path: path, errorDescription: String(data: data ?? Data(), encoding: .utf8)) : nil
if let data = data, let jsonStr = String(data: data, encoding: .utf8), let json = jsonToDictionary(jsonStr) {
if let json = data?.deserializeJSON() {
if let linkDic = json["link"] as? NSDictionary, let linkStr = linkDic["webUrl"] as? String {
link = URL(string: linkStr)
}
@@ -432,7 +432,7 @@ extension OneDriveFileProvider: ExtendedFileProvider {
if let response = response as? HTTPURLResponse {
let code = FileProviderHTTPErrorCode(rawValue: response.statusCode)
serverError = code != nil ? FileProviderOneDriveError(code: code!, path: path, errorDescription: String(data: data ?? Data(), encoding: .utf8)) : nil
if let data = data, let jsonStr = String(data: data, encoding: .utf8), let json = jsonToDictionary(jsonStr) {
if let json = data?.deserializeJSON() {
(dic, keys) = self.mapMediaInfo(json)
}
}
+10 -12
View File
@@ -27,7 +27,7 @@ public final class OneDriveFileObject: FileObject {
}
internal convenience init? (baseURL: URL?, drive: String, jsonStr: String) {
guard let json = jsonToDictionary(jsonStr) else { return nil }
guard let json = jsonStr.deserializeJSON() else { return nil }
self.init(baseURL: baseURL, drive: drive, json: json)
}
@@ -92,15 +92,14 @@ internal extension OneDriveFileProvider {
if let code = (response as? HTTPURLResponse)?.statusCode , code >= 300, let rCode = FileProviderHTTPErrorCode(rawValue: code) {
responseError = FileProviderOneDriveError(code: rCode, path: path, errorDescription: String(data: data ?? Data(), encoding: .utf8))
}
if let data = data, let jsonStr = String(data: data, encoding: .utf8) {
let json = jsonToDictionary(jsonStr)
if let entries = json?["value"] as? [AnyObject] , entries.count > 0 {
if let json = data?.deserializeJSON() {
if let entries = json["value"] as? [AnyObject] , entries.count > 0 {
for entry in entries {
if let entry = entry as? [String: AnyObject], let file = OneDriveFileObject(baseURL: self.baseURL, drive: self.drive, json: entry) {
files.append(file)
}
}
let ncursor: URL? = (json?["@odata.nextLink"] as? String).flatMap { URL(string: $0) }
let ncursor: URL? = (json["@odata.nextLink"] as? String).flatMap { URL(string: $0) }
let hasmore = ncursor != nil
if hasmore {
self.list(path, cursor: ncursor, prevContents: files, completionHandler: completionHandler)
@@ -134,7 +133,7 @@ internal extension OneDriveFileProvider {
responseError = FileProviderOneDriveError(code: rCode, path: targetPath, errorDescription: String(data: data ?? Data(), encoding: .utf8))
}
completionHandler?(responseError ?? error)
self.delegateNotify(.create(path: targetPath), error: responseError ?? error)
self.delegateNotify(operation, error: responseError ?? error)
})
task.taskDescription = operation.json
task.resume()
@@ -161,7 +160,7 @@ internal extension OneDriveFileProvider {
responseError = FileProviderOneDriveError(code: rCode, path: targetPath, errorDescription: String(data: data ?? Data(), encoding: .utf8))
}
completionHandler?(responseError ?? error)
self.delegateNotify(.create(path: targetPath), error: responseError ?? error)
self.delegateNotify(operation, error: responseError ?? error)
})
task.taskDescription = operation.json
task.resume()
@@ -181,15 +180,14 @@ internal extension OneDriveFileProvider {
if let code = (response as? HTTPURLResponse)?.statusCode , code >= 300, let rCode = FileProviderHTTPErrorCode(rawValue: code) {
responseError = FileProviderOneDriveError(code: rCode, path: startPath, errorDescription: String(data: data ?? Data(), encoding: .utf8))
}
if let data = data, let jsonStr = String(data: data, encoding: .utf8) {
let json = jsonToDictionary(jsonStr)
if let entries = json?["value"] as? [AnyObject] , entries.count > 0 {
if let json = data?.deserializeJSON() {
if let entries = json["value"] as? [AnyObject] , entries.count > 0 {
for entry in entries {
if let entry = entry as? [String: AnyObject], let file = OneDriveFileObject(baseURL: self.baseURL, drive: self.drive, json: entry) {
foundItem(file)
}
}
let next: URL? = (json?["@odata.nextLink"] as? String).flatMap { URL(string: $0) }
let next: URL? = (json["@odata.nextLink"] as? String).flatMap { URL(string: $0) }
if let next = next {
self.search(startPath, query: query, next: next, foundItem: foundItem, completionHandler: completionHandler)
} else {
@@ -247,7 +245,7 @@ internal extension OneDriveFileProvider {
add(key: "Location", value: "\(latStr), \(longStr)")
}
if let parent = json["image"] as? [String: Any] ?? json["video"] as? [String: Any], let duration = parent["duration"] as? UInt64 {
add(key: "Duration", value: OneDriveFileProvider.formatshort(interval: TimeInterval(duration) / 1000))
add(key: "Duration", value: (TimeInterval(duration) / 1000).formatshort)
}
if let timeTakenStr = json["takenDateTime"] as? String, let timeTaken = resolve(dateString: timeTakenStr) {
OneDriveFileProvider.dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
+19 -32
View File
@@ -102,57 +102,44 @@ class SessionDelegate: NSObject, URLSessionDataDelegate, URLSessionDownloadDeleg
func urlSession(_ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) {
self.didSendDataHandler?(session, task, bytesSent, totalBytesSent, totalBytesExpectedToSend)
guard let desc = task.taskDescription, let json = jsonToDictionary(desc) else {
return
}
guard let type = json["type"] as? String, let source = json["source"] as? String else {
return
}
let dest = json["dest"] as? String
let op : FileOperationType
switch type {
case "Create":
op = .create(path: source)
case "Copy":
guard let dest = dest else { return }
op = .copy(source: source, destination: dest)
case "Move":
guard let dest = dest else { return }
op = .move(source: source, destination: dest)
case "Modify":
op = .modify(path: source)
case "Remove":
op = .remove(path: source)
case "Link":
guard let dest = dest else { return }
op = .link(link: source, target: dest)
default:
guard let json = task.taskDescription?.deserializeJSON(),
let op = FileOperationType(json: json), let fileProvider = fileProvider else {
return
}
let progress = Float(totalBytesSent) / Float(totalBytesExpectedToSend)
fileProvider?.delegate?.fileproviderProgress(fileProvider!, operation: op, progress: progress)
fileProvider.delegate?.fileproviderProgress(fileProvider, operation: op, progress: progress)
}
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
self.didReceivedData?(session, downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite)
guard let desc = downloadTask.taskDescription, let json = jsonToDictionary(desc), let source = json["source"] as? String, let dest = json["dest"] as? String else {
guard let json = downloadTask.taskDescription?.deserializeJSON(),
let op = FileOperationType(json: json), let fileProvider = fileProvider else {
return
}
fileProvider?.delegate?.fileproviderProgress(fileProvider!, operation: .copy(source: source, destination: dest), progress: Float(totalBytesWritten) / Float(totalBytesExpectedToWrite))
fileProvider.delegate?.fileproviderProgress(fileProvider, operation: op, progress: Float(totalBytesWritten) / Float(totalBytesExpectedToWrite))
}
func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
let deposition: Foundation.URLSession.AuthChallengeDisposition = credential != nil ? .useCredential : .performDefaultHandling
completionHandler(deposition, credential)
authenticate(didReceive: challenge, completionHandler: completionHandler)
}
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
let deposition: Foundation.URLSession.AuthChallengeDisposition = credential != nil ? .useCredential : .performDefaultHandling
completionHandler(deposition, credential)
authenticate(didReceive: challenge, completionHandler: completionHandler)
}
func authenticate(didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
switch (challenge.previousFailureCount, credential != nil) {
case (0...1, true):
completionHandler(.useCredential, credential)
case (0, false):
completionHandler(.useCredential, challenge.proposedCredential)
default:
completionHandler(.performDefaultHandling, nil)
}
}
}
-29
View File
@@ -66,32 +66,3 @@ struct SMBTime {
return Date(timeIntervalSince1970: Double(self.time) / 10000000 - 11644473600)
}
}
extension Data {
init<T>(value: T) {
var value = value
self = Data(buffer: UnsafeBufferPointer(start: &value, count: 1))
}
func scanValue<T>() -> T? {
guard MemoryLayout<T>.size <= self.count else { return nil }
return self.withUnsafeBytes { $0.pointee }
}
func scanValue<T>(start: Int) -> T? {
let length = MemoryLayout<T>.size
guard self.count >= start + length else { return nil }
return self.subdata(in: start..<start+length).withUnsafeBytes { $0.pointee }
}
func scanString(start: Int = 0, length: Int, encoding: String.Encoding) -> String? {
guard self.count >= start + length else { return nil }
return String(data: self.subdata(in: start..<start+length), encoding: encoding)
}
static func mapMemory<T, U>(from: T) -> U? {
guard MemoryLayout<T>.size >= MemoryLayout<U>.size else { return nil }
let data = Data(value: from)
return data.scanValue()
}
}
+1 -1
View File
@@ -243,7 +243,7 @@ extension SMB2 {
if data.count < offset + 48 {
return nil
}
let datestring = data.scanString(start: offset, length: 48, encoding: .utf16)
let datestring = data.scanString(start: offset, length: 48, using: .utf16)
if let datestring = datestring, let date = dateFormatter.date(from: datestring) {
snapshots.append(SMBTime(date: date))
}
+1 -1
View File
@@ -92,7 +92,7 @@ extension SMB2 {
}
let fileNameLen = Int(data.scanValue(start: offset + 8) as UInt32? ?? 0)
let fileName = data.scanString(start: offset + 12, length: fileNameLen, encoding: .utf16) ?? ""
let fileName = data.scanString(start: offset + 12, length: fileNameLen, using: .utf16) ?? ""
result.append((action: action, fileName: fileName))
offset += Int(nextOffset)
+6 -6
View File
@@ -85,7 +85,7 @@ extension SMB2 {
return []
}
let headersize = MemoryLayout.size(ofValue: header)
let fileName = buffer.scanString(start: headersize, length: Int(header.fileNameLength), encoding: .utf16) ?? ""
let fileName = buffer.scanString(start: headersize, length: Int(header.fileNameLength), using: .utf16) ?? ""
result.append((header: header, fileName: fileName))
if header.nextEntryOffset == 0 {
break
@@ -216,12 +216,12 @@ extension SMB2 {
var asAllInformation: (header: FileAllInformationHeader, name: String) {
let header: FileAllInformationHeader = buffer.scanValue()!
let headersize = MemoryLayout<FileAllInformationHeader>.size
let name = buffer.scanString(start: headersize, length: Int(header.nameLength), encoding: .utf16) ?? ""
let name = buffer.scanString(start: headersize, length: Int(header.nameLength), using: .utf16) ?? ""
return (header, name)
}
var asAlternateNameInformation: String {
return buffer.scanString(start: 0, length: buffer.count, encoding: .utf16) ?? ""
return buffer.scanString(start: 0, length: buffer.count, using: .utf16) ?? ""
}
var asAttributeTagInformation: FileAttributeTagInformation {
@@ -280,14 +280,14 @@ extension SMB2 {
var asStreamInformation: (header: FileStreamInformationHeader, name: String) {
let header: FileStreamInformationHeader = buffer.scanValue()!
let headersize = MemoryLayout<FileStreamInformationHeader>.size
let name = buffer.scanString(start: headersize, length: Int(header.streamNameLength), encoding: .utf16) ?? ""
let name = buffer.scanString(start: headersize, length: Int(header.streamNameLength), using: .utf16) ?? ""
return (header, name)
}
var asFsVolumeInformation: (header: FileFsVolumeInformationHeader, name: String) {
let header: FileFsVolumeInformationHeader = buffer.scanValue()!
let headersize = MemoryLayout<FileFsVolumeInformationHeader>.size
let name = buffer.scanString(start: headersize, length: Int(header.labelLength), encoding: .utf16) ?? ""
let name = buffer.scanString(start: headersize, length: Int(header.labelLength), using: .utf16) ?? ""
return (header, name)
}
@@ -302,7 +302,7 @@ extension SMB2 {
var asFsAttributeInformation: (header: FileFsAttributeInformationHeader, name: String) {
let header: FileFsAttributeInformationHeader = buffer.scanValue()!
let headersize = MemoryLayout<FileFsAttributeInformationHeader>.size
let name = buffer.scanString(start: headersize, length: Int(header.nameLength), encoding: .utf16) ?? ""
let name = buffer.scanString(start: headersize, length: Int(header.nameLength), using: .utf16) ?? ""
return (header, name)
}
+13 -16
View File
@@ -564,24 +564,21 @@ struct DavResponse {
}
static func parse(xmlResponse: Data, baseURL: URL?) -> [DavResponse] {
guard let xml = try? AEXMLDocument(xml: xmlResponse) else { return [] }
var result = [DavResponse]()
do {
let xml = try AEXMLDocument(xml: xmlResponse)
var rootnode = xml.root
var responsetag = "response"
for node in rootnode.all ?? [] where node.name.lowercased().hasSuffix("multistatus") {
rootnode = node
var rootnode = xml.root
var responsetag = "response"
for node in rootnode.all ?? [] where node.name.lowercased().hasSuffix("multistatus") {
rootnode = node
}
for node in rootnode.children where node.name.lowercased().hasSuffix("response") {
responsetag = node.name
break
}
for responseNode in rootnode[responsetag].all ?? [] {
if let davResponse = DavResponse(responseNode, baseURL: baseURL) {
result.append(davResponse)
}
for node in rootnode.children where node.name.lowercased().hasSuffix("response") {
responsetag = node.name
break
}
for responseNode in rootnode[responsetag].all ?? [] {
if let davResponse = DavResponse(responseNode, baseURL: baseURL) {
result.append(davResponse)
}
}
} catch _ {
}
return result
}