Files

62 lines
2.9 KiB
Swift

// SPDX-FileCopyrightText: 2026 Kaede Akino
// SPDX-License-Identifier: GPL-3.0-only
import Foundation
import UniformTypeIdentifiers
/// Reads a dropped reference before a provider's temporary file is released.
public nonisolated enum ReferenceDropLoader {
public static func load(_ provider: NSItemProvider) async throws -> String {
if provider.hasItemConformingToTypeIdentifier(UTType.fileURL.identifier) {
return try await withCheckedThrowingContinuation { continuation in
provider.loadObject(ofClass: NSURL.self) { value, error in
do {
guard let url = value as? URL, url.isFileURL else {
throw error ?? CocoaError(.fileReadUnknown)
}
continuation.resume(returning: try read(url))
} catch { continuation.resume(throwing: error) }
}
}
}
let fileTypes = provider.registeredTypeIdentifiers(fileOptions: .openInPlace)
let named = provider.suggestedName?.isEmpty == false
if let type = provider.registeredTypeIdentifiers.first(where: {
guard let type = UTType($0), type.conforms(to: .data), !type.conforms(to: .url) else { return false }
return !type.conforms(to: .text) || named || fileTypes.contains($0)
}) {
return try await withCheckedThrowingContinuation { continuation in
provider.loadFileRepresentation(forTypeIdentifier: type) { url, error in
do {
guard let url else { throw error ?? CocoaError(.fileReadUnknown) }
continuation.resume(returning: try read(url))
} catch { continuation.resume(throwing: error) }
}
}
}
return try await withCheckedThrowingContinuation { continuation in
provider.loadObject(ofClass: NSString.self) { value, error in
guard let text = value as? String else {
continuation.resume(throwing: error ?? CocoaError(.fileReadUnknown))
return
}
guard text.utf8.count <= 1024 * 1024 else {
continuation.resume(throwing: CocoaError(.fileReadTooLarge))
return
}
continuation.resume(returning: text)
}
}
}
private static func read(_ url: URL) throws -> String {
let scoped = url.startAccessingSecurityScopedResource()
defer { if scoped { url.stopAccessingSecurityScopedResource() } }
let values = try url.resourceValues(forKeys: [.isRegularFileKey, .fileSizeKey])
guard values.isRegularFile == true, (values.fileSize ?? 0) <= 1024 * 1024 else {
throw CocoaError(.fileReadTooLarge)
}
return try String(contentsOf: url, encoding: .utf8)
}
}