mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-15 21:45:19 +00:00
104 lines
3.6 KiB
Swift
104 lines
3.6 KiB
Swift
//
|
|
// Data+Serialization.swift
|
|
// ZIPFoundation
|
|
//
|
|
// Copyright © 2017-2020 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
|
|
// Released under the MIT License.
|
|
//
|
|
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
protocol DataSerializable {
|
|
static var size: Int { get }
|
|
init?(data: Data, additionalDataProvider: (Int) throws -> Data)
|
|
var data: Data { get }
|
|
}
|
|
|
|
extension Data {
|
|
enum DataError: Error {
|
|
case unreadableFile
|
|
case unwritableFile
|
|
}
|
|
|
|
func scanValue<T>(start: Int) -> T {
|
|
let subdata = self.subdata(in: start..<start+MemoryLayout<T>.size)
|
|
#if swift(>=5.0)
|
|
return subdata.withUnsafeBytes { $0.load(as: T.self) }
|
|
#else
|
|
return subdata.withUnsafeBytes { $0.pointee }
|
|
#endif
|
|
}
|
|
|
|
static func readStruct<T>(from file: UnsafeMutablePointer<FILE>, at offset: Int) -> T? where T: DataSerializable {
|
|
fseek(file, offset, SEEK_SET)
|
|
guard let data = try? self.readChunk(of: T.size, from: file) else {
|
|
return nil
|
|
}
|
|
let structure = T(data: data, additionalDataProvider: { (additionalDataSize) -> Data in
|
|
return try self.readChunk(of: additionalDataSize, from: file)
|
|
})
|
|
return structure
|
|
}
|
|
|
|
static func consumePart(of size: Int, chunkSize: Int, skipCRC32: Bool = false,
|
|
provider: Provider, consumer: Consumer) throws -> CRC32 {
|
|
var checksum = CRC32(0)
|
|
guard size > 0 else {
|
|
try consumer(Data())
|
|
return checksum
|
|
}
|
|
|
|
let readInOneChunk = (size < chunkSize)
|
|
var chunkSize = readInOneChunk ? size : chunkSize
|
|
var bytesRead = 0
|
|
while bytesRead < size {
|
|
let remainingSize = size - bytesRead
|
|
chunkSize = remainingSize < chunkSize ? remainingSize : chunkSize
|
|
let data = try provider(bytesRead, chunkSize)
|
|
try consumer(data)
|
|
if !skipCRC32 {
|
|
checksum = data.crc32(checksum: checksum)
|
|
}
|
|
bytesRead += chunkSize
|
|
}
|
|
return checksum
|
|
}
|
|
|
|
static func readChunk(of size: Int, from file: UnsafeMutablePointer<FILE>) throws -> Data {
|
|
let alignment = MemoryLayout<UInt>.alignment
|
|
#if swift(>=4.1)
|
|
let bytes = UnsafeMutableRawPointer.allocate(byteCount: size, alignment: alignment)
|
|
#else
|
|
let bytes = UnsafeMutableRawPointer.allocate(bytes: size, alignedTo: alignment)
|
|
#endif
|
|
let bytesRead = fread(bytes, 1, size, file)
|
|
let error = ferror(file)
|
|
if error > 0 {
|
|
throw DataError.unreadableFile
|
|
}
|
|
#if swift(>=4.1)
|
|
return Data(bytesNoCopy: bytes, count: bytesRead, deallocator: .custom({ buf, _ in buf.deallocate() }))
|
|
#else
|
|
let deallocator = Deallocator.custom({ buf, _ in buf.deallocate(bytes: size, alignedTo: 1) })
|
|
return Data(bytesNoCopy: bytes, count: bytesRead, deallocator: deallocator)
|
|
#endif
|
|
}
|
|
|
|
static func write(chunk: Data, to file: UnsafeMutablePointer<FILE>) throws -> Int {
|
|
var sizeWritten = 0
|
|
chunk.withUnsafeBytes { (rawBufferPointer) in
|
|
if let baseAddress = rawBufferPointer.baseAddress, rawBufferPointer.count > 0 {
|
|
let pointer = baseAddress.assumingMemoryBound(to: UInt8.self)
|
|
sizeWritten = fwrite(pointer, 1, chunk.count, file)
|
|
}
|
|
}
|
|
let error = ferror(file)
|
|
if error > 0 {
|
|
throw DataError.unwritableFile
|
|
}
|
|
return sizeWritten
|
|
}
|
|
}
|