module Tins
module FileBinary
module Constants
SEEK_SET = ::File::SEEK_SET
ZERO = "\x00"
BINARY = "\x01-\x1f\x7f-\xff"
if defined?(::Encoding)
ZERO.force_encoding(Encoding::ASCII_8BIT)
BINARY.force_encoding(Encoding::ASCII_8BIT)
end
end
class << self
# Default options can be queried/set via this hash.
attr_accessor :default_options
end
self.default_options = {
offset: 0,
buffer_size: 2 ** 13,
percentage_binary: 30.0,
percentage_zeros: 0.0,
}
# Returns true if this file is considered to be binary, false if it is not
# considered to be binary, and nil if it was empty.
#
# A file is considered to be binary if the percentage of zeros exceeds
# options[:percentage_zeros] or the percentage of binary bytes
# (8-th bit is 1) exceeds options[:percentage_binary] in the
# buffer of size options[:buffer_size] that is checked (beginning
# from offset options[:offset]). If an option isn't given the one
# from FileBinary.default_options is used instead.
def binary?(options = {})
options = FileBinary.default_options.merge(options)
old_pos = tell
seek options[:offset], Constants::SEEK_SET
data = read options[:buffer_size]
!data or data.empty? and return nil
data_size = data.size
data.count(Constants::ZERO).to_f / data_size >
options[:percentage_zeros] / 100.0 and return true
data.count(Constants::BINARY).to_f / data_size >
options[:percentage_binary] / 100.0
ensure
old_pos and seek old_pos, Constants::SEEK_SET
end
# Returns true if FileBinary#binary? returns false, false if
# FileBinary#binary? returns true, and nil otherwise. For an explanation of
# +options+, see FileBinary#binary?.
def ascii?(options = {})
case binary?(options)
when true then false
when false then true
end
end
def self.included(modul)
modul.instance_eval do
extend ClassMethods
end
super
end
module ClassMethods
# Returns true if the file with name +name+ is considered to be binary
# using the FileBinary#binary? method.
def binary?(name, options = {})
open(name, 'rb') { |f| f.binary?(options) }
end
# Returns true if the file with name +name+ is considered to be ascii
# using the FileBinary#ascii? method.
def ascii?(name, options = {})
open(name, 'rb') { |f| f.ascii?(options) }
end
end
end
end
require 'tins/alias'