<commit_before>//
//  SeekableFileInputStream.swift
//  R2Streamer
//
//  Created by <NAME> on 15/01/2017.
//  Copyright © 2017 Readium. All rights reserved.
//

import Foundation

/// FileInputStream errors
///
/// - read: An error while reading data from the fileHandle occured.
/// - fileHandleInitialisation: An error occured while initializing the fileHandle
/// - fileHandle: The fileHandle is not set or invalid.
public enum FileInputStreamError: Error {
    case read
    case fileHandleInitialisation
    case fileHandleUnset
}

extension FileInputStream: Loggable {}

/// <#Description#>
open class FileInputStream: SeekableInputStream {

    /// The path to the file opened by the stream
    private var filePath: String
    
    /// The file handle (== fd) of the file at path `filePath`
    private var fileHandle: FileHandle?

    ///
    private var _streamError: Error?
    override open var streamError: Error? {
        get {
            return _streamError
        }
    }

    /// The status of the fileHandle
    private var _streamStatus: Stream.Status = .notOpen
    override open var streamStatus: Stream.Status {
        get {
            return _streamStatus
        }
    }

    /// The size attribute of the file at `filePath`
    private var _length: UInt64
    override public var length: UInt64 {
        get {
            return _length
        }
    }

    /// Current position in the stream.
    override public var offset: UInt64 {
        get {
            return fileHandle?.offsetInFile ?? 0
        }
    }

    /// True when the current offset is not arrived the the end of the stream.
    override open var hasBytesAvailable: Bool {
        get {
            return offset < _length
        }
    }

    // MARK: - Public methods.

    /// Initialize the object and the input stream meta data for file at 
    /// `fileAtPath`.
    public init?(fileAtPath: String) {
        let attributes: [FileAttributeKey : Any]

        // Does file `atFilePath` exists
        guard FileManager.default.fileExists(atPath: fileAtPath) else {
            FileInputStream.log(level: .error, "File not found: \(fileAtPath).")
            return nil
        }
        filePath = fileAtPath
        // Try to retrieve attributes of `fileAtPath`
        do {
            attributes = try FileManager.default.attributesOfItem(atPath: filePath)
        } catch {
            FileInputStream.log(level: .error, "Exception retrieving attrs for \(filePath).")
            FileInputStream.logValue(level: .error, error)
            return nil
        }
        // Verify the size attribute of the file at `fileAtPath`
        guard let fileSize = attributes[FileAttributeKey.size] as? UInt64 else {
            FileInputStream.log(level: .error, "Error accessing size attribute.")
            return nil
        }
        _length = fileSize
        super.init()
    }

    // MARK: - Open methods.

    /// Open a file handle (<=>fd) for file at path `filePath`.
    override open func open() {
        fileHandle = FileHandle(forReadingAtPath: filePath)
        _streamStatus = .open
    }

    /// Close the file handle.
    override open func close() {
        guard let fileHandle = fileHandle else {
            return
        }
        fileHandle.closeFile()
        _streamStatus = .closed
    }

    // TODO: to implement or delete ?
    override open func getBuffer(_ buffer: UnsafeMutablePointer<UnsafeMutablePointer<UInt8>?>,
                                 length len: UnsafeMutablePointer<Int>) -> Bool {
        return false
    }


    // FIXME: Shouldn't we have smaller read in a loop?
    /// Read up to `maxLength` bytes from `fileHandle` and write them into `buffer`.
    ///
    /// - Parameters:
    ///   - buffer: The destination buffer.
    ///   - maxLength: The maximum number of bytes read.
    /// - Returns: Return the number of bytes read.
    override open func read(_ buffer: UnsafeMutablePointer<UInt8>, maxLength: Int) -> Int {
        let readError = -1
        let data: Data

        guard let fileHandle = fileHandle else {
            return readError
        }
        data = fileHandle.readData(ofLength: maxLength)
        if data.count < maxLength {
            _streamStatus = .atEnd
        }
        data.copyBytes(to: buffer, count: data.count)
        return Int(data.count)
    }

    /// Moves the file pointer to the specified offset within the file.
    ///
    /// - Parameters:
    ///   - offset: The offset.
    ///   - whence: From which position.
    override public func seek(offset: Int64, whence: SeekWhence) {<commit_msg>Code style<commit_after>//
//  SeekableFileInputStream.swift
//  R2Streamer
//
//  Created by <NAME> on 15/01/2017.
//  Copyright © 2017 Readium. All rights reserved.
//

import Foundation

/// FileInputStream errors
///
/// - read: An error while reading data from the fileHandle occured.
/// - fileHandleInitialisation: An error occured while initializing the fileHandle
/// - fileHandle: The fileHandle is not set or invalid.
public enum FileInputStreamError: Error {
    case read
    case fileHandleInitialisation
    case fileHandleUnset
}

extension FileInputStream: Loggable {}

/// <#Description#>
open class FileInputStream: SeekableInputStream {

    /// The path to the file opened by the stream
    private var filePath: String
    
    /// The file handle (== fd) of the file at path `filePath`
    private var fileHandle: FileHandle?

    ///
    private var _streamError: Error?
    override open var streamError: Error? {
        get {
            return _streamError
        }
    }

    /// The status of the fileHandle
    private var _streamStatus: Stream.Status = .notOpen
    override open var streamStatus: Stream.Status {
        get {
            return _streamStatus
        }
    }

    /// The size attribute of the file at `filePath`
    private var _length: UInt64
    override public var length: UInt64 {
        get {
            return _length
        }
    }

    /// Current position in the stream.
    override public var offset: UInt64 {
        get {
            return fileHandle?.offsetInFile ?? 0
        }
    }

    /// True when the current offset is not arrived the the end of the stream.
    override open var hasBytesAvailable: Bool {
        get {
            return offset < _length
        }
    }

    // MARK: - Public methods.

    /// Initialize the object and the input stream meta data for file at 
    /// `fileAtPath`.
    public init?(fileAtPath: String) {
        // Does file `atFilePath` exists
        guard FileManager.default.fileExists(atPath: fileAtPath) else {
            FileInputStream.log(level: .error, "File not found: \(fileAtPath).")
            return nil
        }
        filePath = fileAtPath
        // Try to retrieve attributes of `fileAtPath`
        let attributes: [FileAttributeKey : Any]
        do {
            attributes = try FileManager.default.attributesOfItem(atPath: filePath)
        } catch {
            FileInputStream.log(level: .error, "Exception retrieving attrs for \(filePath).")
            FileInputStream.logValue(level: .error, error)
            return nil
        }
        // Verify the size attribute of the file at `fileAtPath`
        guard let fileSize = attributes[FileAttributeKey.size] as? UInt64 else {
            FileInputStream.log(level: .error, "Error accessing size attribute.")
            return nil
        }
        _length = fileSize
        super.init()
    }

    // MARK: - Open methods.

    /// Open a file handle (<=>fd) for file at path `filePath`.
    override open func open() {
        fileHandle = FileHandle(forReadingAtPath: filePath)
        _streamStatus = .open
    }

    /// Close the file handle.
    override open func close() {
        guard let fileHandle = fileHandle else {
            return
        }
        fileHandle.closeFile()
        _streamStatus = .closed
    }

    // TODO: to implement or delete ?
    override open func getBuffer(_ buffer: UnsafeMutablePointer<UnsafeMutablePointer<UInt8>?>,
                                 length len: UnsafeMutablePointer<Int>) -> Bool {
        return false
    }


    // FIXME: Shouldn't we have smaller read in a loop?
    /// Read up to `maxLength` bytes from `fileHandle` and write them into `buffer`.
    ///
    /// - Parameters:
    ///   - buffer: The destination buffer.
    ///   - maxLength: The maximum number of bytes read.
    /// - Returns: Return the number of bytes read.
    override open func read(_ buffer: UnsafeMutablePointer<UInt8>, maxLength: Int) -> Int {
        let readError = -1

        guard let fileHandle = fileHandle else {
            return readError
        }
        let data = fileHandle.readData(ofLength: maxLength)
        if data.count < maxLength {
            _streamStatus = .atEnd
        }
        data.copyBytes(to: buffer, count: data.count)
        return Int(data.count)
    }

    /// Moves the file pointer to the specified offset within the file.
    ///
    /// - Parameters:
    ///   - offset: The offset.
    ///   - whence: From which position.
    override public func seek(offset: Int64, whence: SeekWhence) {
{'fraction_non_alphanumeric': 0.08985949243001852, 'fraction_numerical': 0.00588171223178303, 'mean_word_length': 2.001634521085322, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4135871', 'n_tokens_mistral': 2490, 'n_tokens_neox': 2400, 'n_words': 853}