104 lines
4.2 KiB
Swift
104 lines
4.2 KiB
Swift
internal import CPlaydate
|
|
|
|
extension File {
|
|
/// An open file. Wraps `SDFile`. The file is closed on deinit if it has
|
|
/// not been closed explicitly.
|
|
public final class Handle {
|
|
let pointer: UnsafeMutableRawPointer
|
|
private var isClosed = false
|
|
|
|
/// Opens the file at `path`.
|
|
public init(path: String, mode: Options) throws(PlaydateError) {
|
|
let pointer = path.withPlaydateCString {
|
|
fileAPI.pointee.open.unsafelyUnwrapped($0, mode.cValue)
|
|
}
|
|
guard let pointer else { throw lastFileError() }
|
|
self.pointer = pointer
|
|
}
|
|
|
|
deinit {
|
|
if !isClosed {
|
|
_ = fileAPI.pointee.close.unsafelyUnwrapped(pointer)
|
|
}
|
|
}
|
|
|
|
/// Closes the file. Further operations are invalid.
|
|
public func close() throws(PlaydateError) {
|
|
guard !isClosed else { return }
|
|
isClosed = true
|
|
if fileAPI.pointee.close.unsafelyUnwrapped(pointer) != 0 { throw lastFileError() }
|
|
}
|
|
|
|
/// Reads up to `buffer.count` bytes into `buffer`. Returns the number
|
|
/// of bytes read; 0 indicates end of file.
|
|
public func read(into buffer: UnsafeMutableRawBufferPointer) throws(PlaydateError) -> Int {
|
|
let result = fileAPI.pointee.read.unsafelyUnwrapped(
|
|
pointer, buffer.baseAddress, UInt32(buffer.count))
|
|
if result < 0 { throw lastFileError() }
|
|
return Int(result)
|
|
}
|
|
|
|
/// Reads up to `length` bytes and returns them.
|
|
public func read(length: Int) throws(PlaydateError) -> [UInt8] {
|
|
var bytes = [UInt8](repeating: 0, count: length)
|
|
let result = bytes.withUnsafeMutableBytes { buffer in
|
|
fileAPI.pointee.read.unsafelyUnwrapped(pointer, buffer.baseAddress, UInt32(buffer.count))
|
|
}
|
|
if result < 0 { throw lastFileError() }
|
|
bytes.removeLast(length - Int(result))
|
|
return bytes
|
|
}
|
|
|
|
/// Writes the buffer to the file. Returns the number of bytes written.
|
|
@discardableResult
|
|
public func write(_ buffer: UnsafeRawBufferPointer) throws(PlaydateError) -> Int {
|
|
let result = fileAPI.pointee.write.unsafelyUnwrapped(
|
|
pointer, buffer.baseAddress, UInt32(buffer.count))
|
|
if result < 0 { throw lastFileError() }
|
|
return Int(result)
|
|
}
|
|
|
|
/// Writes the bytes to the file. Returns the number of bytes written.
|
|
@discardableResult
|
|
public func write(_ bytes: [UInt8]) throws(PlaydateError) -> Int {
|
|
let result = bytes.withUnsafeBytes { buffer in
|
|
fileAPI.pointee.write.unsafelyUnwrapped(pointer, buffer.baseAddress, UInt32(buffer.count))
|
|
}
|
|
if result < 0 { throw lastFileError() }
|
|
return Int(result)
|
|
}
|
|
|
|
/// Writes the string's UTF-8 to the file. Returns the bytes written.
|
|
@discardableResult
|
|
public func write(_ string: String) throws(PlaydateError) -> Int {
|
|
let result = string.withPlaydateUTF8 { bytes, count in
|
|
fileAPI.pointee.write.unsafelyUnwrapped(pointer, bytes, UInt32(count))
|
|
}
|
|
if result < 0 { throw lastFileError() }
|
|
return Int(result)
|
|
}
|
|
|
|
/// Flushes buffered writes to disk. Returns the bytes written.
|
|
@discardableResult
|
|
public func flush() throws(PlaydateError) -> Int {
|
|
let result = fileAPI.pointee.flush.unsafelyUnwrapped(pointer)
|
|
if result < 0 { throw lastFileError() }
|
|
return Int(result)
|
|
}
|
|
|
|
/// The current read/write offset.
|
|
public func tell() throws(PlaydateError) -> Int {
|
|
let result = fileAPI.pointee.tell.unsafelyUnwrapped(pointer)
|
|
if result < 0 { throw lastFileError() }
|
|
return Int(result)
|
|
}
|
|
|
|
/// Moves the read/write offset to `offset` relative to `origin`.
|
|
public func seek(to offset: Int, from origin: SeekOrigin = .start) throws(PlaydateError) {
|
|
if fileAPI.pointee.seek.unsafelyUnwrapped(pointer, Int32(offset), origin.rawValue) != 0 {
|
|
throw lastFileError()
|
|
}
|
|
}
|
|
}
|
|
}
|