Skip to content

Instantly share code, notes, and snippets.

@flocked
Last active March 4, 2023 19:18
Show Gist options
  • Save flocked/eb8a3d5cb7fa987fc2295f92c59445ac to your computer and use it in GitHub Desktop.
Save flocked/eb8a3d5cb7fa987fc2295f92c59445ac to your computer and use it in GitHub Desktop.
OpenSubtitles Hash
import Foundation
public class OSHash {
enum HashError: Error {
case invalidFile
case fileToSmall
}
private static let chunkSize: Int = 65536
private static let byteCount = 8
func hashValue(_ fileURL: URL) throws -> UInt64 {
try self.hashValue(fileURL.path)
}
func hashValue(_ filePath: String) throws -> UInt64 {
guard let fileHandler = FileHandle(forReadingAtPath: filePath) else {
throw HashError.invalidFile
}
let fileDataBegin: Data = fileHandler.readData(ofLength: OSHash.chunkSize) as Data
fileHandler.seekToEndOfFile()
let fileSize: UInt64 = fileHandler.offsetInFile
guard (UInt64(OSHash.chunkSize) <= fileSize) else {
fileHandler.closeFile()
throw HashError.fileToSmall
}
fileHandler.seek(toFileOffset: max(0, fileSize - UInt64(OSHash.chunkSize)))
var hash: UInt64 = fileSize
let fileDataEnd: Data = fileHandler.readData(ofLength: OSHash.chunkSize)
fileDataBegin.withUnsafeBytes { buffer in
let binded = buffer.bindMemory(to: UInt64.self)
let data_bytes = UnsafeBufferPointer<UInt64>(
start: binded.baseAddress,
count: fileDataBegin.count/OSHash.byteCount)
hash = data_bytes.reduce(into: hash, { hash = $0 &+ $1 })
}
fileDataEnd.withUnsafeBytes { buffer in
let binded = buffer.bindMemory(to: UInt64.self)
let data_bytes = UnsafeBufferPointer<UInt64>(
start: binded.baseAddress,
count: fileDataEnd.count/OSHash.byteCount)
hash = data_bytes.reduce(into: hash, { hash = $0 &+ $1 })
}
fileHandler.closeFile()
return hash
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment