66 lines
2.1 KiB
Swift
66 lines
2.1 KiB
Swift
import Foundation
|
|
|
|
/// Checksum algorithms supported for offload/MHL. Element names match
|
|
/// ASC MHL v2.0 spec hash-element vocabulary.
|
|
public enum HashAlgorithm: String, Sendable, CaseIterable {
|
|
case xxh64
|
|
case xxh3
|
|
case xxh128
|
|
case md5
|
|
case sha1
|
|
|
|
public var mhlElement: String {
|
|
rawValue
|
|
}
|
|
|
|
/// In-memory one-shot (test/reference path).
|
|
public static func hashInMemory(_ data: Data, algorithm: HashAlgorithm) -> String {
|
|
switch algorithm {
|
|
case .xxh64:
|
|
return XXHash64.hexString(XXHash64.hash(data))
|
|
case .xxh3:
|
|
return XXH3.hexString64(XXH3.hash64(data))
|
|
case .xxh128:
|
|
return XXH3.hash128(data).hexString
|
|
case .md5:
|
|
return MD5.hexString(data)
|
|
case .sha1:
|
|
return SHA1.hexString(data)
|
|
}
|
|
}
|
|
}
|
|
|
|
extension FileHasher {
|
|
/// Chunked file hash with algorithm dispatch.
|
|
public static func hash(path: String, algorithm: HashAlgorithm) throws -> String {
|
|
switch algorithm {
|
|
case .xxh64:
|
|
return try xxh64(path: path)
|
|
case .md5:
|
|
return try md5(path: path)
|
|
case .xxh3:
|
|
let s = XXH3.Streaming(bits: .h64)
|
|
try streamFile(path: path) { s.update($0) }
|
|
return XXH3.hexString64(s.digest64())
|
|
case .xxh128:
|
|
let s = XXH3.Streaming(bits: .h128)
|
|
try streamFile(path: path) { s.update($0) }
|
|
return s.digest128().hexString
|
|
case .sha1:
|
|
var sha = SHA1()
|
|
try streamFile(path: path) { sha.update($0) }
|
|
return sha.finalize().map { String(format: "%02x", $0) }.joined()
|
|
}
|
|
}
|
|
|
|
static func streamFile(path: String, _ body: (Data) -> Void) throws {
|
|
guard let handle = FileHandle(forReadingAtPath: path) else {
|
|
throw OffloadError.fileNotFound(path)
|
|
}
|
|
defer { try? handle.close() }
|
|
while true {
|
|
guard let chunk = try handle.read(upToCount: chunkSize), !chunk.isEmpty else { break }
|
|
body(chunk)
|
|
}
|
|
}
|
|
}
|