@@ -20,51 +20,56 @@ import Swift
2020
2121enum FileImageSourceError : Error {
2222 case posixError( Int32 )
23- case truncatedRead
23+ case outOfRangeRead
2424}
2525
2626class FileImageSource : ImageSource {
27- private var fd : Int32
27+ private var _mapping : UnsafeRawBufferPointer
2828
2929 public var isMappedImage : Bool { return false }
3030
3131 private var _path : String
3232 public var path : String ? { return _path }
3333
34- public lazy var bounds : Bounds ? = {
35- let size = lseek ( fd, 0 , SEEK_END)
36- if size < 0 {
37- return nil
38- }
39- return Bounds ( base: 0 , size: Size ( size) )
40- } ( )
34+ public var bounds : Bounds ? {
35+ return Bounds ( base: 0 , size: Size ( _mapping. count) )
36+ }
4137
4238 public init ( path: String ) throws {
4339 _path = path
44- fd = _swift_open ( path, O_RDONLY, 0 )
40+ let fd = _swift_open ( path, O_RDONLY, 0 )
4541 if fd < 0 {
4642 throw FileImageSourceError . posixError ( _swift_get_errno ( ) )
4743 }
44+ defer { close ( fd) }
45+ let size = lseek ( fd, 0 , SEEK_END)
46+ if size < 0 {
47+ throw FileImageSourceError . posixError ( _swift_get_errno ( ) )
48+ }
49+ let base = mmap ( nil , Int ( size) , PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0 )
50+ if base == nil || base! == UnsafeRawPointer ( bitPattern: - 1 ) ! {
51+ throw FileImageSourceError . posixError ( _swift_get_errno ( ) )
52+ }
53+ _mapping = UnsafeRawBufferPointer ( start: base, count: Int ( size) )
4854 }
4955
5056 deinit {
51- close ( fd)
57+ munmap ( UnsafeMutableRawPointer ( mutating: _mapping. baseAddress) ,
58+ _mapping. count)
5259 }
5360
5461 public func fetch< T> ( from addr: Address ,
5562 into buffer: UnsafeMutableBufferPointer < T > ) throws {
56- while true {
57- let size = MemoryLayout < T > . stride * buffer. count
58- let result = pread ( fd, buffer. baseAddress, size, off_t ( addr) )
59-
60- if result < 0 {
61- throw FileImageSourceError . posixError ( _swift_get_errno ( ) )
63+ let start = Int ( addr)
64+ _ = try buffer. withMemoryRebound ( to: UInt8 . self) { byteBuf in
65+ guard _mapping. indices. contains ( start) else {
66+ throw FileImageSourceError . outOfRangeRead
6267 }
63-
64- if result != size {
65- throw FileImageSourceError . truncatedRead
68+ let slice = _mapping [ start ... ]
69+ guard slice . count >= byteBuf . count else {
70+ throw FileImageSourceError . outOfRangeRead
6671 }
67- break
72+ byteBuf . update ( from : slice )
6873 }
6974 }
7075}
0 commit comments