diff --git a/Library/Homebrew/Gemfile b/Library/Homebrew/Gemfile index 065dd6c83effd..9ae5e10c8a1fa 100644 --- a/Library/Homebrew/Gemfile +++ b/Library/Homebrew/Gemfile @@ -17,6 +17,7 @@ gem "simplecov", require: false gem "activesupport" gem "concurrent-ruby" gem "mechanize" +gem "patchelf" gem "plist" gem "rubocop-performance" gem "rubocop-rspec" diff --git a/Library/Homebrew/Gemfile.lock b/Library/Homebrew/Gemfile.lock index e051a5b9cf6c2..9792e6b755b8a 100644 --- a/Library/Homebrew/Gemfile.lock +++ b/Library/Homebrew/Gemfile.lock @@ -8,6 +8,7 @@ GEM tzinfo (~> 1.1) zeitwerk (~> 2.2) ast (2.4.0) + bindata (2.4.4) concurrent-ruby (1.1.5) connection_pool (2.2.2) coveralls (0.8.23) @@ -20,6 +21,8 @@ GEM docile (1.3.2) domain_name (0.5.20190701) unf (>= 0.0.5, < 1.0.0) + elftools (1.1.2) + bindata (~> 2) hpricot (0.8.6) http-cookie (1.0.3) domain_name (~> 0.5) @@ -53,6 +56,8 @@ GEM parallel parser (2.7.0.2) ast (~> 2.4.0) + patchelf (1.0.0) + elftools (~> 1.1) plist (3.5.0) rainbow (3.0.0) rdiscount (2.2.0.1) @@ -123,6 +128,7 @@ DEPENDENCIES coveralls (~> 0.8) mechanize parallel_tests + patchelf plist ronn rspec diff --git a/Library/Homebrew/vendor/bundle/bundler/setup.rb b/Library/Homebrew/vendor/bundle/bundler/setup.rb index d29d9804970c9..f790724f19dff 100644 --- a/Library/Homebrew/vendor/bundle/bundler/setup.rb +++ b/Library/Homebrew/vendor/bundle/bundler/setup.rb @@ -5,51 +5,54 @@ path = File.expand_path('..', __FILE__) $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/concurrent-ruby-1.1.5/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/i18n-1.8.2/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/minitest-5.13.0/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/minitest-5.14.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/thread_safe-0.3.6/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/tzinfo-1.2.6/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/zeitwerk-2.2.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/activesupport-6.0.2.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ast-2.4.0/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/bindata-2.4.4/lib" $:.unshift "#{path}/" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/connection_pool-2.2.2/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-19/2.6.0/json-2.3.0" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-13/2.6.0-static/json-2.3.0" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/json-2.3.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/docile-1.3.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov-html-0.10.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov-0.16.1/lib" -$:.unshift "#{path}/../../../../../../../../Library/Ruby/Gems/2.6.0/gems/sync-0.5.0/lib" +$:.unshift "#{path}/../../portable-ruby/2.6.3/lib/ruby/gems/2.6.0/gems/sync-0.5.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/tins-1.24.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/term-ansicolor-1.7.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/thor-1.0.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/coveralls-0.8.23/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/diff-lcs-1.3/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-19/2.6.0/unf_ext-0.0.7.6" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-13/2.6.0-static/unf_ext-0.0.7.6" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unf_ext-0.0.7.6/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unf-0.1.4/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/domain_name-0.5.20190701/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-19/2.6.0/hpricot-0.8.6" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/elftools-1.1.2/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-13/2.6.0-static/hpricot-0.8.6" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/hpricot-0.8.6/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/http-cookie-1.0.3/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-19/2.6.0/jaro_winkler-1.5.4" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-13/2.6.0-static/jaro_winkler-1.5.4" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/jaro_winkler-1.5.4/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mime-types-data-3.2019.1009/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mime-types-3.3.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/net-http-digest_auth-1.4.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/net-http-persistent-3.1.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mini_portile2-2.4.0/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-19/2.6.0/nokogiri-1.10.7" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-13/2.6.0-static/nokogiri-1.10.7" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/nokogiri-1.10.7/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ntlm-http-0.1.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/webrobots-0.1.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mechanize-2.7.6/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mustache-1.1.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel-1.19.1/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel_tests-2.30.0/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel_tests-2.31.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parser-2.7.0.2/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/patchelf-1.0.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/plist-3.5.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rainbow-3.0.0/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-19/2.6.0/rdiscount-2.2.0.1" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-13/2.6.0-static/rdiscount-2.2.0.1" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rdiscount-2.2.0.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ronn-0.7.3/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-support-3.9.2/lib" @@ -61,7 +64,7 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-retry-0.6.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-wait-0.0.9/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-progressbar-1.10.1/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unicode-display_width-1.6.0/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unicode-display_width-1.6.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-0.79.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-performance-1.5.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rspec-1.37.1/lib" diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata.rb new file mode 100644 index 0000000000000..02a8390443f5a --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata.rb @@ -0,0 +1,37 @@ +# BinData -- Binary data manipulator. +# Copyright (c) 2007 - 2018 Dion Mendel. + +require 'bindata/version' +require 'bindata/array' +require 'bindata/bits' +require 'bindata/buffer' +require 'bindata/choice' +require 'bindata/count_bytes_remaining' +require 'bindata/delayed_io' +require 'bindata/float' +require 'bindata/int' +require 'bindata/primitive' +require 'bindata/record' +require 'bindata/rest' +require 'bindata/skip' +require 'bindata/string' +require 'bindata/stringz' +require 'bindata/struct' +require 'bindata/trace' +require 'bindata/uint8_array' +require 'bindata/virtual' +require 'bindata/alignment' +require 'bindata/warnings' + +# = BinData +# +# A declarative way to read and write structured binary data. +# +# A full reference manual is available online at +# https://github.com/dmendel/bindata/wiki +# +# == License +# +# BinData is released under the same license as Ruby. +# +# Copyright (c) 2007 - 2018 Dion Mendel. diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/alignment.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/alignment.rb new file mode 100644 index 0000000000000..44fa0ba93a921 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/alignment.rb @@ -0,0 +1,79 @@ +require 'bindata/base_primitive' + +module BinData + # Resets the stream alignment to the next byte. This is + # only useful when using bit-based primitives. + # + # class MyRec < BinData::Record + # bit4 :a + # resume_byte_alignment + # bit4 :b + # end + # + # MyRec.read("\x12\x34") #=> {"a" => 1, "b" => 3} + # + class ResumeByteAlignment < BinData::Base + def clear?; true; end + def assign(val); end + def snapshot; nil; end + def do_num_bytes; 0; end + + def do_read(io) + io.reset_read_bits + end + + def do_write(io) + io.flushbits + end + end + + # A monkey patch to force byte-aligned primitives to + # become bit-aligned. This allows them to be used at + # non byte based boundaries. + # + # class BitString < BinData::String + # bit_aligned + # end + # + # class MyRecord < BinData::Record + # bit4 :preamble + # bit_string :str, length: 2 + # end + # + module BitAligned + class BitAlignedIO + def initialize(io) + @io = io + end + def readbytes(n) + n.times.inject("") do |bytes, _| + bytes << @io.readbits(8, :big).chr + end + end + end + + def bit_aligned? + true + end + + def read_and_return_value(io) + super(BitAlignedIO.new(io)) + end + + def do_num_bytes + super.to_f + end + + def do_write(io) + value_to_binary_string(_value).each_byte { |v| io.writebits(v, 8, :big) } + end + end + + def BasePrimitive.bit_aligned + include BitAligned + end + + def Primitive.bit_aligned + fail "'bit_aligned' is not needed for BinData::Primitives" + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/array.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/array.rb new file mode 100644 index 0000000000000..c2f3aabba30f7 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/array.rb @@ -0,0 +1,336 @@ +require 'bindata/base' +require 'bindata/dsl' + +module BinData + # An Array is a list of data objects of the same type. + # + # require 'bindata' + # + # data = "\x03\x04\x05\x06\x07\x08\x09" + # + # obj = BinData::Array.new(type: :int8, initial_length: 6) + # obj.read(data) #=> [3, 4, 5, 6, 7, 8] + # + # obj = BinData::Array.new(type: :int8, + # read_until: -> { index == 1 }) + # obj.read(data) #=> [3, 4] + # + # obj = BinData::Array.new(type: :int8, + # read_until: -> { element >= 6 }) + # obj.read(data) #=> [3, 4, 5, 6] + # + # obj = BinData::Array.new(type: :int8, + # read_until: -> { array[index] + array[index - 1] == 13 }) + # obj.read(data) #=> [3, 4, 5, 6, 7] + # + # obj = BinData::Array.new(type: :int8, read_until: :eof) + # obj.read(data) #=> [3, 4, 5, 6, 7, 8, 9] + # + # == Parameters + # + # Parameters may be provided at initialisation to control the behaviour of + # an object. These params are: + # + # :type:: The symbol representing the data type of the + # array elements. If the type is to have params + # passed to it, then it should be provided as + # [type_symbol, hash_params]. + # :initial_length:: The initial length of the array. + # :read_until:: While reading, elements are read until this + # condition is true. This is typically used to + # read an array until a sentinel value is found. + # The variables +index+, +element+ and +array+ + # are made available to any lambda assigned to + # this parameter. If the value of this parameter + # is the symbol :eof, then the array will read + # as much data from the stream as possible. + # + # Each data object in an array has the variable +index+ made available + # to any lambda evaluated as a parameter of that data object. + class Array < BinData::Base + extend DSLMixin + include Enumerable + + dsl_parser :array + arg_processor :array + + mandatory_parameter :type + optional_parameters :initial_length, :read_until + mutually_exclusive_parameters :initial_length, :read_until + + def initialize_shared_instance + @element_prototype = get_parameter(:type) + if get_parameter(:read_until) == :eof + extend ReadUntilEOFPlugin + elsif has_parameter?(:read_until) + extend ReadUntilPlugin + elsif has_parameter?(:initial_length) + extend InitialLengthPlugin + end + + super + end + + def initialize_instance + @element_list = nil + end + + def clear? + @element_list.nil? || elements.all?(&:clear?) + end + + def assign(array) + raise ArgumentError, "can't set a nil value for #{debug_name}" if array.nil? + + @element_list = to_storage_formats(array.to_ary) + end + + def snapshot + elements.collect(&:snapshot) + end + + def find_index(obj) + elements.index(obj) + end + alias index find_index + + # Returns the first index of +obj+ in self. + # + # Uses equal? for the comparator. + def find_index_of(obj) + elements.index { |el| el.equal?(obj) } + end + + def push(*args) + insert(-1, *args) + self + end + alias << push + + def unshift(*args) + insert(0, *args) + self + end + + def concat(array) + insert(-1, *array.to_ary) + self + end + + def insert(index, *objs) + extend_array(index - 1) + elements.insert(index, *to_storage_formats(objs)) + self + end + + # Returns the element at +index+. + def [](arg1, arg2 = nil) + if arg1.respond_to?(:to_int) && arg2.nil? + slice_index(arg1.to_int) + elsif arg1.respond_to?(:to_int) && arg2.respond_to?(:to_int) + slice_start_length(arg1.to_int, arg2.to_int) + elsif arg1.is_a?(Range) && arg2.nil? + slice_range(arg1) + else + raise TypeError, "can't convert #{arg1} into Integer" unless arg1.respond_to?(:to_int) + raise TypeError, "can't convert #{arg2} into Integer" unless arg2.respond_to?(:to_int) + end + end + alias slice [] + + def slice_index(index) + extend_array(index) + at(index) + end + + def slice_start_length(start, length) + elements[start, length] + end + + def slice_range(range) + elements[range] + end + private :slice_index, :slice_start_length, :slice_range + + # Returns the element at +index+. Unlike +slice+, if +index+ is out + # of range the array will not be automatically extended. + def at(index) + elements[index] + end + + # Sets the element at +index+. + def []=(index, value) + extend_array(index) + elements[index].assign(value) + end + + # Returns the first element, or the first +n+ elements, of the array. + # If the array is empty, the first form returns nil, and the second + # form returns an empty array. + def first(n = nil) + if n.nil? && empty? + # explicitly return nil as arrays grow automatically + nil + elsif n.nil? + self[0] + else + self[0, n] + end + end + + # Returns the last element, or the last +n+ elements, of the array. + # If the array is empty, the first form returns nil, and the second + # form returns an empty array. + def last(n = nil) + if n.nil? + self[-1] + else + n = length if n > length + self[-n, n] + end + end + + def length + elements.length + end + alias size length + + def empty? + length.zero? + end + + # Allow this object to be used in array context. + def to_ary + collect { |el| el } + end + + def each + elements.each { |el| yield el } + end + + def debug_name_of(child) #:nodoc: + index = find_index_of(child) + "#{debug_name}[#{index}]" + end + + def offset_of(child) #:nodoc: + index = find_index_of(child) + sum = sum_num_bytes_below_index(index) + + child.bit_aligned? ? sum.floor : sum.ceil + end + + def do_write(io) #:nodoc: + elements.each { |el| el.do_write(io) } + end + + def do_num_bytes #:nodoc: + sum_num_bytes_for_all_elements + end + + #--------------- + private + + def extend_array(max_index) + max_length = max_index + 1 + while elements.length < max_length + append_new_element + end + end + + def to_storage_formats(els) + els.collect { |el| new_element(el) } + end + + def elements + @element_list ||= [] + end + + def append_new_element + element = new_element + elements << element + element + end + + def new_element(value = nil) + @element_prototype.instantiate(value, self) + end + + def sum_num_bytes_for_all_elements + sum_num_bytes_below_index(length) + end + + def sum_num_bytes_below_index(index) + (0...index).inject(0) do |sum, i| + nbytes = elements[i].do_num_bytes + + if nbytes.is_a?(Integer) + sum.ceil + nbytes + else + sum + nbytes + end + end + end + end + + class ArrayArgProcessor < BaseArgProcessor + def sanitize_parameters!(obj_class, params) #:nodoc: + # ensure one of :initial_length and :read_until exists + unless params.has_at_least_one_of?(:initial_length, :read_until) + params[:initial_length] = 0 + end + + params.warn_replacement_parameter(:length, :initial_length) + params.warn_replacement_parameter(:read_length, :initial_length) + params.must_be_integer(:initial_length) + + params.merge!(obj_class.dsl_params) + params.sanitize_object_prototype(:type) + end + end + + # Logic for the :read_until parameter + module ReadUntilPlugin + def do_read(io) + loop do + element = append_new_element + element.do_read(io) + variables = { index: self.length - 1, element: self.last, array: self } + break if eval_parameter(:read_until, variables) + end + end + end + + # Logic for the read_until: :eof parameter + module ReadUntilEOFPlugin + def do_read(io) + loop do + element = append_new_element + begin + element.do_read(io) + rescue EOFError, IOError + elements.pop + break + end + end + end + end + + # Logic for the :initial_length parameter + module InitialLengthPlugin + def do_read(io) + elements.each { |el| el.do_read(io) } + end + + def elements + if @element_list.nil? + @element_list = [] + eval_parameter(:initial_length).times do + @element_list << new_element + end + end + + @element_list + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/base.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/base.rb new file mode 100644 index 0000000000000..2053844ef7500 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/base.rb @@ -0,0 +1,336 @@ +require 'bindata/framework' +require 'bindata/io' +require 'bindata/lazy' +require 'bindata/name' +require 'bindata/params' +require 'bindata/registry' +require 'bindata/sanitize' + +module BinData + # This is the abstract base class for all data objects. + class Base + extend AcceptedParametersPlugin + include Framework + include RegisterNamePlugin + + class << self + # Instantiates this class and reads from +io+, returning the newly + # created data object. +args+ will be used when instantiating. + def read(io, *args, &block) + obj = self.new(*args) + obj.read(io, &block) + obj + end + + # The arg processor for this class. + def arg_processor(name = nil) + @arg_processor ||= nil + + if name + @arg_processor = "#{name}_arg_processor".gsub(/(?:^|_)(.)/) { $1.upcase }.to_sym + elsif @arg_processor.is_a? Symbol + @arg_processor = BinData.const_get(@arg_processor).new + elsif @arg_processor.nil? + @arg_processor = superclass.arg_processor + else + @arg_processor + end + end + + # The name of this class as used by Records, Arrays etc. + def bindata_name + RegisteredClasses.underscore_name(name) + end + + # Call this method if this class is abstract and not to be used. + def unregister_self + RegisteredClasses.unregister(name) + end + + # Registers all subclasses of this class for use + def register_subclasses #:nodoc: + singleton_class.send(:undef_method, :inherited) + define_singleton_method(:inherited) do |subclass| + RegisteredClasses.register(subclass.name, subclass) + register_subclasses + end + end + + private :unregister_self, :register_subclasses + end + + # Register all subclasses of this class. + register_subclasses + + # Set the initial arg processor. + arg_processor :base + + # Creates a new data object. + # + # Args are optional, but if present, must be in the following order. + # + # +value+ is a value that is +assign+ed immediately after initialization. + # + # +parameters+ is a hash containing symbol keys. Some parameters may + # reference callable objects (methods or procs). + # + # +parent+ is the parent data object (e.g. struct, array, choice) this + # object resides under. + # + def initialize(*args) + value, @params, @parent = extract_args(args) + + initialize_shared_instance + initialize_instance + assign(value) if value + end + + attr_accessor :parent + protected :parent= + + # Creates a new data object based on this instance. + # + # All parameters will be be duplicated. Use this method + # when creating multiple objects with the same parameters. + def new(value = nil, parent = nil) + obj = clone + obj.parent = parent if parent + obj.initialize_instance + obj.assign(value) if value + + obj + end + + # Returns the result of evaluating the parameter identified by +key+. + # + # +overrides+ is an optional +parameters+ like hash that allow the + # parameters given at object construction to be overridden. + # + # Returns nil if +key+ does not refer to any parameter. + def eval_parameter(key, overrides = nil) + value = get_parameter(key) + if value.is_a?(Symbol) || value.respond_to?(:arity) + lazy_evaluator.lazy_eval(value, overrides) + else + value + end + end + + # Returns a lazy evaluator for this object. + def lazy_evaluator #:nodoc: + @lazy ||= LazyEvaluator.new(self) + end + + # Returns the parameter referenced by +key+. + # Use this method if you are sure the parameter is not to be evaluated. + # You most likely want #eval_parameter. + def get_parameter(key) + @params[key] + end + + # Returns whether +key+ exists in the +parameters+ hash. + def has_parameter?(key) + @params.has_parameter?(key) + end + + # Resets the internal state to that of a newly created object. + def clear + initialize_instance + end + + # Reads data into this data object. + def read(io, &block) + io = BinData::IO::Read.new(io) unless BinData::IO::Read === io + + start_read do + clear + do_read(io) + end + block.call(self) if block_given? + + self + end + + # Writes the value for this data object to +io+. + def write(io, &block) + io = BinData::IO::Write.new(io) unless BinData::IO::Write === io + + do_write(io) + io.flush + + block.call(self) if block_given? + + self + end + + # Returns the number of bytes it will take to write this data object. + def num_bytes + do_num_bytes.ceil + end + + # Returns the string representation of this data object. + def to_binary_s(&block) + io = BinData::IO.create_string_io + write(io, &block) + io.rewind + io.read + end + + # Returns the hexadecimal string representation of this data object. + def to_hex(&block) + to_binary_s(&block).unpack('H*')[0] + end + + # Return a human readable representation of this data object. + def inspect + snapshot.inspect + end + + # Return a string representing this data object. + def to_s + snapshot.to_s + end + + # Work with Ruby's pretty-printer library. + def pretty_print(pp) #:nodoc: + pp.pp(snapshot) + end + + # Override and delegate =~ as it is defined in Object. + def =~(other) + snapshot =~ other + end + + # Returns a user friendly name of this object for debugging purposes. + def debug_name + if @parent + @parent.debug_name_of(self) + else + "obj" + end + end + + # Returns the offset (in bytes) of this object with respect to its most + # distant ancestor. + def abs_offset + if @parent + @parent.abs_offset + @parent.offset_of(self) + else + 0 + end + end + + # Returns the offset (in bytes) of this object with respect to its parent. + def rel_offset + if @parent + @parent.offset_of(self) + else + 0 + end + end + + def ==(other) #:nodoc: + # double dispatch + other == snapshot + end + + # A version of +respond_to?+ used by the lazy evaluator. It doesn't + # reinvoke the evaluator so as to avoid infinite evaluation loops. + def safe_respond_to?(symbol, include_private = false) #:nodoc: + base_respond_to?(symbol, include_private) + end + + alias base_respond_to? respond_to? + + #--------------- + private + + def extract_args(args) + self.class.arg_processor.extract_args(self.class, args) + end + + def start_read + top_level_set(:in_read, true) + yield + ensure + top_level_set(:in_read, false) + end + + # Is this object tree currently being read? Used by BasePrimitive. + def reading? + top_level_get(:in_read) + end + + def top_level_set(sym, value) + top_level.instance_variable_set("@tl_#{sym}", value) + end + + def top_level_get(sym) + tl = top_level + tl.instance_variable_defined?("@tl_#{sym}") && + tl.instance_variable_get("@tl_#{sym}") + end + + def top_level + if parent.nil? + tl = self + else + tl = parent + tl = tl.parent while tl.parent + end + + tl + end + + def binary_string(str) + str.to_s.dup.force_encoding(Encoding::BINARY) + end + end + + # ArgProcessors process the arguments passed to BinData::Base.new into + # the form required to initialise the BinData object. + # + # Any passed parameters are sanitized so the BinData object doesn't + # need to perform error checking on the parameters. + class BaseArgProcessor + @@empty_hash = Hash.new.freeze + + # Takes the arguments passed to BinData::Base.new and + # extracts [value, sanitized_parameters, parent]. + def extract_args(obj_class, obj_args) + value, params, parent = separate_args(obj_class, obj_args) + sanitized_params = SanitizedParameters.sanitize(params, obj_class) + + [value, sanitized_params, parent] + end + + # Separates the arguments passed to BinData::Base.new into + # [value, parameters, parent]. Called by #extract_args. + def separate_args(_obj_class, obj_args) + args = obj_args.dup + value = parameters = parent = nil + + if args.length > 1 && args.last.is_a?(BinData::Base) + parent = args.pop + end + + if args.length > 0 && args.last.is_a?(Hash) + parameters = args.pop + end + + if args.length > 0 + value = args.pop + end + + parameters ||= @@empty_hash + + [value, parameters, parent] + end + + # Performs sanity checks on the given parameters. + # This method converts the parameters to the form expected + # by the data object. + def sanitize_parameters!(obj_class, obj_params) + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/base_primitive.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/base_primitive.rb new file mode 100644 index 0000000000000..3b2b4839e793d --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/base_primitive.rb @@ -0,0 +1,248 @@ +require 'bindata/base' + +module BinData + # A BinData::BasePrimitive object is a container for a value that has a + # particular binary representation. A value corresponds to a primitive type + # such as as integer, float or string. Only one value can be contained by + # this object. This value can be read from or written to an IO stream. + # + # require 'bindata' + # + # obj = BinData::Uint8.new(initial_value: 42) + # obj #=> 42 + # obj.assign(5) + # obj #=> 5 + # obj.clear + # obj #=> 42 + # + # obj = BinData::Uint8.new(value: 42) + # obj #=> 42 + # obj.assign(5) + # obj #=> 42 + # + # obj = BinData::Uint8.new(assert: 3) + # obj.read("\005") #=> BinData::ValidityError: value is '5' but expected '3' + # + # obj = BinData::Uint8.new(assert: -> { value < 5 }) + # obj.read("\007") #=> BinData::ValidityError: value not as expected + # + # == Parameters + # + # Parameters may be provided at initialisation to control the behaviour of + # an object. These params include those for BinData::Base as well as: + # + # [:initial_value] This is the initial value to use before one is + # either #read or explicitly set with #value=. + # [:value] The object will always have this value. + # Calls to #value= are ignored when + # using this param. While reading, #value + # will return the value of the data read from the + # IO, not the result of the :value param. + # [:assert] Raise an error unless the value read or assigned + # meets this criteria. The variable +value+ is + # made available to any lambda assigned to this + # parameter. A boolean return indicates success + # or failure. Any other return is compared to + # the value just read in. + # [:asserted_value] Equivalent to :assert and :value. + # + class BasePrimitive < BinData::Base + unregister_self + + optional_parameters :initial_value, :value, :assert, :asserted_value + mutually_exclusive_parameters :initial_value, :value + mutually_exclusive_parameters :asserted_value, :value, :assert + + def initialize_shared_instance + extend InitialValuePlugin if has_parameter?(:initial_value) + extend ValuePlugin if has_parameter?(:value) + extend AssertPlugin if has_parameter?(:assert) + extend AssertedValuePlugin if has_parameter?(:asserted_value) + super + end + + def initialize_instance + @value = nil + end + + def clear? #:nodoc: + @value.nil? + end + + def assign(val) + raise ArgumentError, "can't set a nil value for #{debug_name}" if val.nil? + + raw_val = val.respond_to?(:snapshot) ? val.snapshot : val + @value = + begin + raw_val.dup + rescue TypeError + # can't dup Fixnums + raw_val + end + end + + def snapshot + _value + end + + def value + snapshot + end + + def value=(val) + assign(val) + end + + def respond_to?(symbol, include_private = false) #:nodoc: + child = snapshot + child.respond_to?(symbol, include_private) || super + end + + def method_missing(symbol, *args, &block) #:nodoc: + child = snapshot + if child.respond_to?(symbol) + self.class.class_eval \ + "def #{symbol}(*args, &block);" \ + " snapshot.#{symbol}(*args, &block);" \ + "end" + child.__send__(symbol, *args, &block) + else + super + end + end + + def <=>(other) + snapshot <=> other + end + + def eql?(other) + # double dispatch + other.eql?(snapshot) + end + + def hash + snapshot.hash + end + + def do_read(io) #:nodoc: + @value = read_and_return_value(io) + end + + def do_write(io) #:nodoc: + io.writebytes(value_to_binary_string(_value)) + end + + def do_num_bytes #:nodoc: + value_to_binary_string(_value).length + end + + #--------------- + private + + # The unmodified value of this data object. Note that #snapshot calls this + # method. This indirection is so that #snapshot can be overridden in + # subclasses to modify the presentation value. + def _value + @value != nil ? @value : sensible_default + end + + # Logic for the :value parameter + module ValuePlugin + def assign(val) + # Ignored + end + + def _value + reading? ? @value : eval_parameter(:value) + end + end + + # Logic for the :initial_value parameter + module InitialValuePlugin + def _value + @value != nil ? @value : eval_parameter(:initial_value) + end + end + + # Logic for the :assert parameter + module AssertPlugin + def assign(val) + super(val) + assert! + end + + def do_read(io) #:nodoc: + super(io) + assert! + end + + def assert! + current_value = snapshot + expected = eval_parameter(:assert, value: current_value) + + msg = + if !expected + "value '#{current_value}' not as expected" + elsif expected != true && current_value != expected + "value is '#{current_value}' but expected '#{expected}'" + else + nil + end + + raise ValidityError, "#{msg} for #{debug_name}" if msg + end + end + + # Logic for the :asserted_value parameter + module AssertedValuePlugin + def assign(val) + assert_value(val) + super(val) + end + + def _value + reading? ? @value : eval_parameter(:asserted_value) + end + + def do_read(io) #:nodoc: + super(io) + assert! + end + + def assert! + assert_value(snapshot) + end + + def assert_value(current_value) + expected = eval_parameter(:asserted_value, value: current_value) + if current_value != expected + raise ValidityError, + "value is '#{current_value}' but " \ + "expected '#{expected}' for #{debug_name}" + end + end + end + + ########################################################################### + # To be implemented by subclasses + + # Return the string representation that +val+ will take when written. + def value_to_binary_string(val) + raise NotImplementedError + end + + # Read a number of bytes from +io+ and return the value they represent. + def read_and_return_value(io) + raise NotImplementedError + end + + # Return a sensible default for this data. + def sensible_default + raise NotImplementedError + end + + # To be implemented by subclasses + ########################################################################### + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/bits.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/bits.rb new file mode 100644 index 0000000000000..b04c4fbf2712a --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/bits.rb @@ -0,0 +1,186 @@ +require 'thread' +require 'bindata/base_primitive' + +module BinData + # Defines a number of classes that contain a bit based integer. + # The integer is defined by endian and number of bits. + + module BitField #:nodoc: all + @@mutex = Mutex.new + + class << self + def define_class(name, nbits, endian, signed = :unsigned) + @@mutex.synchronize do + unless BinData.const_defined?(name) + new_class = Class.new(BinData::BasePrimitive) + BitField.define_methods(new_class, nbits, endian.to_sym, signed.to_sym) + RegisteredClasses.register(name, new_class) + + BinData.const_set(name, new_class) + end + end + + BinData.const_get(name) + end + + def define_methods(bit_class, nbits, endian, signed) + bit_class.module_eval <<-END + #{create_params_code(nbits)} + + def assign(val) + #{create_nbits_code(nbits)} + #{create_clamp_code(nbits, signed)} + super(val) + end + + def do_write(io) + #{create_nbits_code(nbits)} + val = _value + #{create_int2uint_code(nbits, signed)} + io.writebits(val, #{nbits}, :#{endian}) + end + + def do_num_bytes + #{create_nbits_code(nbits)} + #{create_do_num_bytes_code(nbits)} + end + + def bit_aligned? + true + end + + #--------------- + private + + def read_and_return_value(io) + #{create_nbits_code(nbits)} + val = io.readbits(#{nbits}, :#{endian}) + #{create_uint2int_code(nbits, signed)} + val + end + + def sensible_default + 0 + end + END + end + + def create_params_code(nbits) + if nbits == :nbits + "mandatory_parameter :nbits" + else + "" + end + end + + def create_nbits_code(nbits) + if nbits == :nbits + "nbits = eval_parameter(:nbits)" + else + "" + end + end + + def create_do_num_bytes_code(nbits) + if nbits == :nbits + "nbits / 8.0" + else + nbits / 8.0 + end + end + + def create_clamp_code(nbits, signed) + if nbits == :nbits + create_dynamic_clamp_code(signed) + else + create_fixed_clamp_code(nbits, signed) + end + end + + def create_dynamic_clamp_code(signed) + if signed == :signed + max = "max = (1 << (nbits - 1)) - 1" + min = "min = -(max + 1)" + else + max = "max = (1 << nbits) - 1" + min = "min = 0" + end + + "#{max}; #{min}; val = (val < min) ? min : (val > max) ? max : val" + end + + def create_fixed_clamp_code(nbits, signed) + if nbits == 1 && signed == :signed + raise "signed bitfield must have more than one bit" + end + + if signed == :signed + max = (1 << (nbits - 1)) - 1 + min = -(max + 1) + else + min = 0 + max = (1 << nbits) - 1 + end + + clamp = "(val < #{min}) ? #{min} : (val > #{max}) ? #{max} : val" + + if nbits == 1 + # allow single bits to be used as booleans + clamp = "(val == true) ? 1 : (not val) ? 0 : #{clamp}" + end + + "val = #{clamp}" + end + + def create_int2uint_code(nbits, signed) + if signed != :signed + "" + elsif nbits == :nbits + "val &= (1 << nbits) - 1" + else + "val &= #{(1 << nbits) - 1}" + end + end + + def create_uint2int_code(nbits, signed) + if signed != :signed + "" + elsif nbits == :nbits + "val -= (1 << nbits) if (val >= (1 << (nbits - 1)))" + else + "val -= #{1 << nbits} if (val >= #{1 << (nbits - 1)})" + end + end + end + end + + # Create classes for dynamic bitfields + { + "Bit" => :big, + "BitLe" => :little, + "Sbit" => [:big, :signed], + "SbitLe" => [:little, :signed], + }.each_pair { |name, args| BitField.define_class(name, :nbits, *args) } + + # Create classes on demand + module BitFieldFactory + def const_missing(name) + mappings = { + /^Bit(\d+)$/ => :big, + /^Bit(\d+)le$/ => :little, + /^Sbit(\d+)$/ => [:big, :signed], + /^Sbit(\d+)le$/ => [:little, :signed] + } + + mappings.each_pair do |regex, args| + if regex =~ name.to_s + nbits = $1.to_i + return BitField.define_class(name, nbits, *args) + end + end + + super(name) + end + end + BinData.extend BitFieldFactory +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/buffer.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/buffer.rb new file mode 100644 index 0000000000000..b504c6cdf3161 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/buffer.rb @@ -0,0 +1,117 @@ +require 'bindata/base' +require 'bindata/dsl' + +module BinData + # A Buffer is conceptually a substream within a data stream. It has a + # defined size and it will always read or write the exact number of bytes to + # fill the buffer. Short reads will skip over unused bytes and short writes + # will pad the substream with "\0" bytes. + # + # require 'bindata' + # + # obj = BinData::Buffer.new(length: 5, type: [:string, {value: "abc"}]) + # obj.to_binary_s #=> "abc\000\000" + # + # + # class MyBuffer < BinData::Buffer + # default_parameter length: 8 + # + # endian :little + # + # uint16 :num1 + # uint16 :num2 + # # padding occurs here + # end + # + # obj = MyBuffer.read("\001\000\002\000\000\000\000\000") + # obj.num1 #=> 1 + # obj.num1 #=> 2 + # obj.raw_num_bytes #=> 4 + # obj.num_bytes #=> 8 + # + # + # class StringTable < BinData::Record + # endian :little + # + # uint16 :table_size_in_bytes + # buffer :strings, length: :table_size_in_bytes do + # array read_until: :eof do + # uint8 :len + # string :str, length: :len + # end + # end + # end + # + # + # == Parameters + # + # Parameters may be provided at initialisation to control the behaviour of + # an object. These params are: + # + # :length:: The number of bytes in the buffer. + # :type:: The single type inside the buffer. Use a struct if + # multiple fields are required. + class Buffer < BinData::Base + extend DSLMixin + + dsl_parser :buffer + arg_processor :buffer + + mandatory_parameters :length, :type + + def initialize_instance + @type = get_parameter(:type).instantiate(nil, self) + end + + # The number of bytes used, ignoring the padding imposed by the buffer. + def raw_num_bytes + @type.num_bytes + end + + def clear? + @type.clear? + end + + def assign(val) + @type.assign(val) + end + + def snapshot + @type.snapshot + end + + def respond_to?(symbol, include_private = false) #:nodoc: + @type.respond_to?(symbol, include_private) || super + end + + def method_missing(symbol, *args, &block) #:nodoc: + @type.__send__(symbol, *args, &block) + end + + def do_read(io) #:nodoc: + io.with_buffer(eval_parameter(:length)) do + @type.do_read(io) + end + end + + def do_write(io) #:nodoc: + io.with_buffer(eval_parameter(:length)) do + @type.do_write(io) + end + end + + def do_num_bytes #:nodoc: + eval_parameter(:length) + end + end + + class BufferArgProcessor < BaseArgProcessor + include MultiFieldArgSeparator + + def sanitize_parameters!(obj_class, params) + params.merge!(obj_class.dsl_params) + params.must_be_integer(:length) + params.sanitize_object_prototype(:type) + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/choice.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/choice.rb new file mode 100644 index 0000000000000..a06f36e3cf695 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/choice.rb @@ -0,0 +1,186 @@ +require 'bindata/base' +require 'bindata/dsl' + +module BinData + # A Choice is a collection of data objects of which only one is active + # at any particular time. Method calls will be delegated to the active + # choice. + # + # require 'bindata' + # + # type1 = [:string, {value: "Type1"}] + # type2 = [:string, {value: "Type2"}] + # + # choices = {5 => type1, 17 => type2} + # a = BinData::Choice.new(choices: choices, selection: 5) + # a # => "Type1" + # + # choices = [ type1, type2 ] + # a = BinData::Choice.new(choices: choices, selection: 1) + # a # => "Type2" + # + # choices = [ nil, nil, nil, type1, nil, type2 ] + # a = BinData::Choice.new(choices: choices, selection: 3) + # a # => "Type1" + # + # + # Chooser = Struct.new(:choice) + # mychoice = Chooser.new + # mychoice.choice = 'big' + # + # choices = {'big' => :uint16be, 'little' => :uint16le} + # a = BinData::Choice.new(choices: choices, copy_on_change: true, + # selection: -> { mychoice.choice }) + # a.assign(256) + # a.to_binary_s #=> "\001\000" + # + # mychoice.choice = 'little' + # a.to_binary_s #=> "\000\001" + # + # == Parameters + # + # Parameters may be provided at initialisation to control the behaviour of + # an object. These params are: + # + # :choices:: Either an array or a hash specifying the possible + # data objects. The format of the + # array/hash.values is a list of symbols + # representing the data object type. If a choice + # is to have params passed to it, then it should + # be provided as [type_symbol, hash_params]. An + # implementation constraint is that the hash may + # not contain symbols as keys, with the exception + # of :default. :default is to be used when then + # :selection does not exist in the :choices hash. + # :selection:: An index/key into the :choices array/hash which + # specifies the currently active choice. + # :copy_on_change:: If set to true, copy the value of the previous + # selection to the current selection whenever the + # selection changes. Default is false. + class Choice < BinData::Base + extend DSLMixin + + dsl_parser :choice + arg_processor :choice + + mandatory_parameters :choices, :selection + optional_parameter :copy_on_change + + def initialize_shared_instance + extend CopyOnChangePlugin if eval_parameter(:copy_on_change) == true + super + end + + def initialize_instance + @choices = {} + @last_selection = nil + end + + # Returns the current selection. + def selection + selection = eval_parameter(:selection) + if selection.nil? + raise IndexError, ":selection returned nil for #{debug_name}" + end + selection + end + + def respond_to?(symbol, include_private = false) #:nodoc: + current_choice.respond_to?(symbol, include_private) || super + end + + def method_missing(symbol, *args, &block) #:nodoc: + current_choice.__send__(symbol, *args, &block) + end + + %w(clear? assign snapshot do_read do_write do_num_bytes).each do |m| + module_eval <<-END + def #{m}(*args) + current_choice.#{m}(*args) + end + END + end + + #--------------- + private + + def current_choice + current_selection = selection + @choices[current_selection] ||= instantiate_choice(current_selection) + end + + def instantiate_choice(selection) + prototype = get_parameter(:choices)[selection] + if prototype.nil? + raise IndexError, "selection '#{selection}' does not exist in :choices for #{debug_name}" + end + prototype.instantiate(nil, self) + end + end + + class ChoiceArgProcessor < BaseArgProcessor + def sanitize_parameters!(obj_class, params) #:nodoc: + params.merge!(obj_class.dsl_params) + + params.sanitize_choices(:choices) do |choices| + hash_choices = choices_as_hash(choices) + ensure_valid_keys(hash_choices) + hash_choices + end + end + + #------------- + private + + def choices_as_hash(choices) + if choices.respond_to?(:to_ary) + key_array_by_index(choices.to_ary) + else + choices + end + end + + def key_array_by_index(array) + result = {} + array.each_with_index do |el, i| + result[i] = el unless el.nil? + end + result + end + + def ensure_valid_keys(choices) + if choices.key?(nil) + raise ArgumentError, ":choices hash may not have nil key" + end + if choices.keys.detect { |key| key.is_a?(Symbol) && key != :default } + raise ArgumentError, ":choices hash may not have symbols for keys" + end + end + end + + # Logic for the :copy_on_change parameter + module CopyOnChangePlugin + def current_choice + obj = super + copy_previous_value(obj) + obj + end + + def copy_previous_value(obj) + current_selection = selection + prev = get_previous_choice(current_selection) + obj.assign(prev) unless prev.nil? + remember_current_selection(current_selection) + end + + def get_previous_choice(selection) + if @last_selection && selection != @last_selection + @choices[@last_selection] + end + end + + def remember_current_selection(selection) + @last_selection = selection + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/count_bytes_remaining.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/count_bytes_remaining.rb new file mode 100644 index 0000000000000..c90b7ba268768 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/count_bytes_remaining.rb @@ -0,0 +1,34 @@ +require "bindata/base_primitive" + +module BinData + # Counts the number of bytes remaining in the input stream from the current + # position to the end of the stream. This only makes sense for seekable + # streams. + # + # require 'bindata' + # + # class A < BinData::Record + # count_bytes_remaining :bytes_remaining + # string :all_data, read_length: :bytes_remaining + # end + # + # obj = A.read("abcdefghij") + # obj.all_data #=> "abcdefghij" + # + class CountBytesRemaining < BinData::BasePrimitive + #--------------- + private + + def value_to_binary_string(val) + "" + end + + def read_and_return_value(io) + io.num_bytes_remaining + end + + def sensible_default + 0 + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/delayed_io.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/delayed_io.rb new file mode 100644 index 0000000000000..d0bae60300cba --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/delayed_io.rb @@ -0,0 +1,190 @@ +require 'bindata/base' +require 'bindata/dsl' + +module BinData + # BinData declarations are evaluated in a single pass. + # However, some binary formats require multi pass processing. A common + # reason is seeking backwards in the input stream. + # + # DelayedIO supports multi pass processing. It works by ignoring the normal + # #read or #write calls. The user must explicitly call the #read_now! or + # #write_now! methods to process an additional pass. This additional pass + # must specify the abs_offset of the I/O operation. + # + # require 'bindata' + # + # obj = BinData::DelayedIO.new(read_abs_offset: 3, type: :uint16be) + # obj.read("\x00\x00\x00\x11\x12") + # obj #=> 0 + # + # obj.read_now! + # obj #=> 0x1112 + # + # - OR - + # + # obj.read("\x00\x00\x00\x11\x12") { obj.read_now! } #=> 0x1122 + # + # obj.to_binary_s { obj.write_now! } #=> "\x00\x00\x00\x11\x12" + # + # You can use the +auto_call_delayed_io+ keyword to cause #read and #write to + # automatically perform the extra passes. + # + # class ReversePascalString < BinData::Record + # auto_call_delayed_io + # + # delayed_io :str, read_abs_offset: 0 do + # string read_length: :len + # end + # count_bytes_remaining :total_size + # skip to_abs_offset: -> { total_size - 1 } + # uint8 :len, value: -> { str.length } + # end + # + # s = ReversePascalString.read("hello\x05") + # s.to_binary_s #=> "hello\x05" + # + # + # == Parameters + # + # Parameters may be provided at initialisation to control the behaviour of + # an object. These params are: + # + # :read_abs_offset:: The abs_offset to start reading at. + # :type:: The single type inside the delayed io. Use + # a struct if multiple fields are required. + class DelayedIO < BinData::Base + extend DSLMixin + + dsl_parser :delayed_io + arg_processor :delayed_io + + mandatory_parameters :read_abs_offset, :type + + def initialize_instance + @type = get_parameter(:type).instantiate(nil, self) + @abs_offset = nil + @read_io = nil + @write_io = nil + end + + def clear? + @type.clear? + end + + def assign(val) + @type.assign(val) + end + + def snapshot + @type.snapshot + end + + def num_bytes + @type.num_bytes + end + + def respond_to?(symbol, include_private = false) #:nodoc: + @type.respond_to?(symbol, include_private) || super + end + + def method_missing(symbol, *args, &block) #:nodoc: + @type.__send__(symbol, *args, &block) + end + + def abs_offset + @abs_offset || eval_parameter(:read_abs_offset) + end + + # Sets the +abs_offset+ to use when writing this object. + def abs_offset=(offset) + @abs_offset = offset + end + + def rel_offset + abs_offset + end + + def do_read(io) #:nodoc: + @read_io = io + end + + def do_write(io) #:nodoc: + @write_io = io + end + + def do_num_bytes #:nodoc: + 0 + end + + # DelayedIO objects aren't read when #read is called. + # The reading is delayed until this method is called. + def read_now! + raise IOError, "read from where?" unless @read_io + + @read_io.seekbytes(abs_offset - @read_io.offset) + start_read do + @type.do_read(@read_io) + end + end + + # DelayedIO objects aren't written when #write is called. + # The writing is delayed until this method is called. + def write_now! + raise IOError, "write to where?" unless @write_io + @write_io.seekbytes(abs_offset - @write_io.offset) + @type.do_write(@write_io) + end + end + + class DelayedIoArgProcessor < BaseArgProcessor + include MultiFieldArgSeparator + + def sanitize_parameters!(obj_class, params) + params.merge!(obj_class.dsl_params) + params.must_be_integer(:read_abs_offset) + params.sanitize_object_prototype(:type) + end + end + + # Add +auto_call_delayed_io+ keyword to BinData::Base. + class Base + class << self + # The +auto_call_delayed_io+ keyword sets a data object tree to perform + # multi pass I/O automatically. + def auto_call_delayed_io + return if DelayedIO.method_defined? :initialize_instance_without_record_io + + include AutoCallDelayedIO + DelayedIO.send(:alias_method, :initialize_instance_without_record_io, :initialize_instance) + DelayedIO.send(:define_method, :initialize_instance) do + if @parent && !defined? @delayed_io_recorded + @delayed_io_recorded = true + list = top_level_get(:delayed_ios) + list << self if list + end + + initialize_instance_without_record_io + end + end + end + + module AutoCallDelayedIO + def initialize_shared_instance + top_level_set(:delayed_ios, []) + super + end + + def read(io) + super(io) { top_level_get(:delayed_ios).each(&:read_now!) } + end + + def write(io, *_) + super(io) { top_level_get(:delayed_ios).each(&:write_now!) } + end + + def num_bytes + to_binary_s.size + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/dsl.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/dsl.rb new file mode 100644 index 0000000000000..44b25f266b651 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/dsl.rb @@ -0,0 +1,484 @@ +module BinData + # Extracts args for Records and Buffers. + # + # Foo.new(bar: "baz) is ambiguous as to whether :bar is a value or parameter. + # + # BaseArgExtractor always assumes :bar is parameter. This extractor correctly + # identifies it as value or parameter. + module MultiFieldArgSeparator + def separate_args(obj_class, obj_args) + value, parameters, parent = super(obj_class, obj_args) + + if parameters_is_value?(obj_class, value, parameters) + value = parameters + parameters = {} + end + + [value, parameters, parent] + end + + def parameters_is_value?(obj_class, value, parameters) + if value.nil? && !parameters.empty? + field_names_in_parameters?(obj_class, parameters) + else + false + end + end + + def field_names_in_parameters?(obj_class, parameters) + field_names = obj_class.fields.field_names + param_keys = parameters.keys + + !(field_names & param_keys).empty? + end + end + + # BinData classes that are part of the DSL must be extended by this. + module DSLMixin + def dsl_parser(parser_type = nil) + @dsl_parser ||= begin + parser_type ||= superclass.dsl_parser.parser_type + DSLParser.new(self, parser_type) + end + end + + def method_missing(symbol, *args, &block) #:nodoc: + dsl_parser.__send__(symbol, *args, &block) + end + + # Assert object is not an array or string. + def to_ary; nil; end + def to_str; nil; end + + # A DSLParser parses and accumulates field definitions of the form + # + # type name, params + # + # where: + # * +type+ is the under_scored name of a registered type + # * +name+ is the (possible optional) name of the field + # * +params+ is a hash containing any parameters + # + class DSLParser + def initialize(the_class, parser_type) + raise "unknown parser type #{parser_type}" unless parser_abilities[parser_type] + + @the_class = the_class + @parser_type = parser_type + @validator = DSLFieldValidator.new(the_class, self) + @endian = nil + end + + attr_reader :parser_type + + def endian(endian = nil) + if endian + set_endian(endian) + elsif @endian.nil? + set_endian(parent_attribute(:endian)) + end + @endian + end + + def search_prefix(*args) + @search_prefix ||= parent_attribute(:search_prefix, []).dup + + prefix = args.collect(&:to_sym).compact + unless prefix.empty? + if fields? + dsl_raise SyntaxError, "search_prefix must be called before defining fields" + end + + @search_prefix = prefix.concat(@search_prefix) + end + + @search_prefix + end + + def hide(*args) + if option?(:hidden_fields) + @hide ||= parent_attribute(:hide, []).dup + + hidden = args.collect(&:to_sym).compact + @hide.concat(hidden) + + @hide + end + end + + def fields + @fields ||= SanitizedFields.new(hints, parent_fields) + end + + def dsl_params + abilities = parser_abilities[@parser_type] + send(abilities.at(0), abilities.at(1)) + end + + def method_missing(*args, &block) + ensure_hints + parse_and_append_field(*args, &block) + end + + #------------- + private + + def parser_abilities + @abilities ||= { + struct: [:to_struct_params, :struct, [:multiple_fields, :optional_fieldnames, :hidden_fields]], + array: [:to_object_params, :type, [:multiple_fields, :optional_fieldnames]], + buffer: [:to_object_params, :type, [:multiple_fields, :optional_fieldnames, :hidden_fields]], + choice: [:to_choice_params, :choices, [:multiple_fields, :all_or_none_fieldnames, :fieldnames_are_values]], + delayed_io: [:to_object_params, :type, [:multiple_fields, :optional_fieldnames, :hidden_fields]], + primitive: [:to_struct_params, :struct, [:multiple_fields, :optional_fieldnames]], + skip: [:to_object_params, :until_valid, [:multiple_fields, :optional_fieldnames]], + } + end + + def option?(opt) + parser_abilities[@parser_type].at(2).include?(opt) + end + + def ensure_hints + endian + search_prefix + end + + def hints + { endian: endian, search_prefix: search_prefix } + end + + def set_endian(endian) + if endian + if fields? + dsl_raise SyntaxError, "endian must be called before defining fields" + end + if !valid_endian?(endian) + dsl_raise ArgumentError, "unknown value for endian '#{endian}'" + end + + if endian == :big_and_little + DSLBigAndLittleEndianHandler.handle(@the_class) + end + + @endian = endian + end + end + + def valid_endian?(endian) + [:big, :little, :big_and_little].include?(endian) + end + + def parent_fields + parent_attribute(:fields) + end + + def fields? + defined?(@fields) && !@fields.empty? + end + + def parse_and_append_field(*args, &block) + parser = DSLFieldParser.new(hints, *args, &block) + begin + @validator.validate_field(parser.name) + append_field(parser.type, parser.name, parser.params) + rescue Exception => err + dsl_raise err.class, err.message + end + end + + def append_field(type, name, params) + fields.add_field(type, name, params) + rescue BinData::UnRegisteredTypeError => err + raise TypeError, "unknown type '#{err.message}'" + end + + def parent_attribute(attr, default = nil) + parent = @the_class.superclass + parser = parent.respond_to?(:dsl_parser) ? parent.dsl_parser : nil + if parser && parser.respond_to?(attr) + parser.send(attr) + else + default + end + end + + def dsl_raise(exception, msg) + backtrace = caller + backtrace.shift while %r{bindata/dsl.rb} =~ backtrace.first + + raise exception, "#{msg} in #{@the_class}", backtrace + end + + def to_object_params(key) + case fields.length + when 0 + {} + when 1 + {key => fields[0].prototype} + else + {key=> [:struct, to_struct_params]} + end + end + + def to_choice_params(key) + if fields.empty? + {} + elsif fields.all_field_names_blank? + {key => fields.collect(&:prototype)} + else + choices = {} + fields.each { |f| choices[f.name] = f.prototype } + {key => choices} + end + end + + def to_struct_params(*unused) + result = {fields: fields} + if !endian.nil? + result[:endian] = endian + end + if !search_prefix.empty? + result[:search_prefix] = search_prefix + end + if option?(:hidden_fields) && !hide.empty? + result[:hide] = hide + end + + result + end + end + + # Handles the :big_and_little endian option. + # This option creates two subclasses, each handling + # :big or :little endian. + class DSLBigAndLittleEndianHandler + class << self + def handle(bnl_class) + make_class_abstract(bnl_class) + create_subclasses_with_endian(bnl_class) + override_new_in_class(bnl_class) + delegate_field_creation(bnl_class) + fixup_subclass_hierarchy(bnl_class) + end + + def make_class_abstract(bnl_class) + bnl_class.send(:unregister_self) + end + + def create_subclasses_with_endian(bnl_class) + instance_eval "class ::#{bnl_class}Be < ::#{bnl_class}; endian :big; end" + instance_eval "class ::#{bnl_class}Le < ::#{bnl_class}; endian :little; end" + end + + def override_new_in_class(bnl_class) + endian_classes = { + big: class_with_endian(bnl_class, :big), + little: class_with_endian(bnl_class, :little), + } + bnl_class.define_singleton_method(:new) do |*args| + if self == bnl_class + _, options, _ = arg_processor.separate_args(self, args) + delegate = endian_classes[options[:endian]] + return delegate.new(*args) if delegate + end + + super(*args) + end + end + + def delegate_field_creation(bnl_class) + endian_classes = { + big: class_with_endian(bnl_class, :big), + little: class_with_endian(bnl_class, :little), + } + + parser = bnl_class.dsl_parser + parser.define_singleton_method(:parse_and_append_field) do |*args, &block| + endian_classes[:big].send(*args, &block) + endian_classes[:little].send(*args, &block) + end + end + + def fixup_subclass_hierarchy(bnl_class) + parent = bnl_class.superclass + if obj_attribute(parent, :endian) == :big_and_little + be_subclass = class_with_endian(bnl_class, :big) + be_parent = class_with_endian(parent, :big) + be_fields = obj_attribute(be_parent, :fields) + + le_subclass = class_with_endian(bnl_class, :little) + le_parent = class_with_endian(parent, :little) + le_fields = obj_attribute(le_parent, :fields) + + be_subclass.dsl_parser.define_singleton_method(:parent_fields) do + be_fields + end + le_subclass.dsl_parser.define_singleton_method(:parent_fields) do + le_fields + end + end + end + + def class_with_endian(class_name, endian) + hints = { + endian: endian, + search_prefix: class_name.dsl_parser.search_prefix, + } + RegisteredClasses.lookup(class_name, hints) + end + + def obj_attribute(obj, attr) + obj.dsl_parser.send(attr) + end + end + end + + # Extracts the details from a field declaration. + class DSLFieldParser + def initialize(hints, symbol, *args, &block) + @hints = hints + @type = symbol + @name = name_from_field_declaration(args) + @params = params_from_field_declaration(args, &block) + end + + attr_reader :type, :name, :params + + def name_from_field_declaration(args) + name, _ = args + if name == "" || name.is_a?(Hash) + nil + else + name + end + end + + def params_from_field_declaration(args, &block) + params = params_from_args(args) + + if block_given? + params.merge(params_from_block(&block)) + else + params + end + end + + def params_from_args(args) + name, params = args + params = name if name.is_a?(Hash) + + params || {} + end + + def params_from_block(&block) + bindata_classes = { + array: BinData::Array, + buffer: BinData::Buffer, + choice: BinData::Choice, + delayed_io: BinData::DelayedIO, + skip: BinData::Skip, + struct: BinData::Struct, + } + + if bindata_classes.include?(@type) + parser = DSLParser.new(bindata_classes[@type], @type) + parser.endian(@hints[:endian]) + parser.search_prefix(*@hints[:search_prefix]) + parser.instance_eval(&block) + + parser.dsl_params + else + {} + end + end + end + + # Validates a field defined in a DSLMixin. + class DSLFieldValidator + def initialize(the_class, parser) + @the_class = the_class + @dsl_parser = parser + end + + def validate_field(name) + if must_not_have_a_name_failed?(name) + raise SyntaxError, "field must not have a name" + end + + if all_or_none_names_failed?(name) + raise SyntaxError, "fields must either all have names, or none must have names" + end + + if must_have_a_name_failed?(name) + raise SyntaxError, "field must have a name" + end + + ensure_valid_name(name) + end + + def ensure_valid_name(name) + if name && !option?(:fieldnames_are_values) + if malformed_name?(name) + raise NameError.new("", name), "field '#{name}' is an illegal fieldname" + end + + if duplicate_name?(name) + raise SyntaxError, "duplicate field '#{name}'" + end + + if name_shadows_method?(name) + raise NameError.new("", name), "field '#{name}' shadows an existing method" + end + + if name_is_reserved?(name) + raise NameError.new("", name), "field '#{name}' is a reserved name" + end + end + end + + def must_not_have_a_name_failed?(name) + option?(:no_fieldnames) && !name.nil? + end + + def must_have_a_name_failed?(name) + option?(:mandatory_fieldnames) && name.nil? + end + + def all_or_none_names_failed?(name) + if option?(:all_or_none_fieldnames) && !fields.empty? + all_names_blank = fields.all_field_names_blank? + no_names_blank = fields.no_field_names_blank? + + (!name.nil? && all_names_blank) || (name.nil? && no_names_blank) + else + false + end + end + + def malformed_name?(name) + /^[a-z_]\w*$/ !~ name.to_s + end + + def duplicate_name?(name) + fields.field_name?(name) + end + + def name_shadows_method?(name) + @the_class.method_defined?(name) + end + + def name_is_reserved?(name) + BinData::Struct::RESERVED.include?(name.to_sym) + end + + def fields + @dsl_parser.fields + end + + def option?(opt) + @dsl_parser.send(:option?, opt) + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/float.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/float.rb new file mode 100644 index 0000000000000..98a470817f4a4 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/float.rb @@ -0,0 +1,83 @@ +require 'bindata/base_primitive' + +module BinData + # Defines a number of classes that contain a floating point number. + # The float is defined by precision and endian. + + module FloatingPoint #:nodoc: all + class << self + PRECISION = { + single: 4, + double: 8, + } + + PACK_CODE = { + [:single, :little] => 'e', + [:single, :big] => 'g', + [:double, :little] => 'E', + [:double, :big] => 'G', + } + + def define_methods(float_class, precision, endian) + float_class.module_eval <<-END + def do_num_bytes + #{create_num_bytes_code(precision)} + end + + #--------------- + private + + def sensible_default + 0.0 + end + + def value_to_binary_string(val) + #{create_to_binary_s_code(precision, endian)} + end + + def read_and_return_value(io) + #{create_read_code(precision, endian)} + end + END + end + + def create_num_bytes_code(precision) + PRECISION[precision] + end + + def create_read_code(precision, endian) + nbytes = PRECISION[precision] + unpack = PACK_CODE[[precision, endian]] + + "io.readbytes(#{nbytes}).unpack('#{unpack}').at(0)" + end + + def create_to_binary_s_code(precision, endian) + pack = PACK_CODE[[precision, endian]] + + "[val].pack('#{pack}')" + end + end + end + + + # Single precision floating point number in little endian format + class FloatLe < BinData::BasePrimitive + FloatingPoint.define_methods(self, :single, :little) + end + + # Single precision floating point number in big endian format + class FloatBe < BinData::BasePrimitive + FloatingPoint.define_methods(self, :single, :big) + end + + # Double precision floating point number in little endian format + class DoubleLe < BinData::BasePrimitive + FloatingPoint.define_methods(self, :double, :little) + end + + # Double precision floating point number in big endian format + class DoubleBe < BinData::BasePrimitive + FloatingPoint.define_methods(self, :double, :big) + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/framework.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/framework.rb new file mode 100644 index 0000000000000..ab652c2de310b --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/framework.rb @@ -0,0 +1,75 @@ +module BinData + # Error raised when unexpected results occur when reading data from IO. + class ValidityError < StandardError ; end + + # All methods provided by the framework are to be implemented or overridden + # by subclasses of BinData::Base. + module Framework + # Initializes the state of the object. All instance variables that + # are used by the object must be initialized here. + def initialize_instance + end + + # Initialises state that is shared by objects with the same parameters. + # + # This should only be used when optimising for performance. Instance + # variables set here, and changes to the singleton class will be shared + # between all objects that are initialized with the same parameters. + # This method is called only once for a particular set of parameters. + def initialize_shared_instance + end + + # Returns true if the object has not been changed since creation. + def clear? + raise NotImplementedError + end + + # Assigns the value of +val+ to this data object. Note that +val+ must + # always be deep copied to ensure no aliasing problems can occur. + def assign(val) + raise NotImplementedError + end + + # Returns a snapshot of this data object. + def snapshot + raise NotImplementedError + end + + # Returns the debug name of +child+. This only needs to be implemented + # by objects that contain child objects. + def debug_name_of(child) #:nodoc: + debug_name + end + + # Returns the offset of +child+. This only needs to be implemented + # by objects that contain child objects. + def offset_of(child) #:nodoc: + 0 + end + + # Is this object aligned on non-byte boundaries? + def bit_aligned? + false + end + + # Reads the data for this data object from +io+. + def do_read(io) #:nodoc: + raise NotImplementedError + end + + # Writes the value for this data to +io+. + def do_write(io) #:nodoc: + raise NotImplementedError + end + + # Returns the number of bytes it will take to write this data. + def do_num_bytes #:nodoc: + raise NotImplementedError + end + + # Set visibility requirements of methods to implement + public :clear?, :assign, :snapshot, :debug_name_of, :offset_of + protected :initialize_instance, :initialize_shared_instance + protected :do_read, :do_write, :do_num_bytes + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/int.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/int.rb new file mode 100644 index 0000000000000..0becfd54a9737 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/int.rb @@ -0,0 +1,212 @@ +require 'thread' +require 'bindata/base_primitive' + +module BinData + # Defines a number of classes that contain an integer. The integer + # is defined by endian, signedness and number of bytes. + + module Int #:nodoc: all + @@mutex = Mutex.new + + class << self + def define_class(name, nbits, endian, signed) + @@mutex.synchronize do + unless BinData.const_defined?(name) + new_class = Class.new(BinData::BasePrimitive) + Int.define_methods(new_class, nbits, endian.to_sym, signed.to_sym) + RegisteredClasses.register(name, new_class) + + BinData.const_set(name, new_class) + end + end + + BinData.const_get(name) + end + + def define_methods(int_class, nbits, endian, signed) + raise "nbits must be divisible by 8" unless (nbits % 8).zero? + + int_class.module_eval <<-END + def assign(val) + #{create_clamp_code(nbits, signed)} + super(val) + end + + def do_num_bytes + #{nbits / 8} + end + + #--------------- + private + + def sensible_default + 0 + end + + def value_to_binary_string(val) + #{create_clamp_code(nbits, signed)} + #{create_to_binary_s_code(nbits, endian, signed)} + end + + def read_and_return_value(io) + #{create_read_code(nbits, endian, signed)} + end + END + end + + #------------- + private + + def create_clamp_code(nbits, signed) + if signed == :signed + max = (1 << (nbits - 1)) - 1 + min = -(max + 1) + else + max = (1 << nbits) - 1 + min = 0 + end + + "val = (val < #{min}) ? #{min} : (val > #{max}) ? #{max} : val" + end + + def create_read_code(nbits, endian, signed) + read_str = create_raw_read_code(nbits, endian, signed) + + if need_signed_conversion_code?(nbits, signed) + "val = #{read_str} ; #{create_uint2int_code(nbits)}" + else + read_str + end + end + + def create_raw_read_code(nbits, endian, signed) + # special case 8bit integers for speed + if nbits == 8 + "io.readbytes(1).ord" + else + unpack_str = create_read_unpack_code(nbits, endian, signed) + assemble_str = create_read_assemble_code(nbits, endian, signed) + + "(#{unpack_str} ; #{assemble_str})" + end + end + + def create_read_unpack_code(nbits, endian, signed) + nbytes = nbits / 8 + pack_directive = pack_directive(nbits, endian, signed) + + "ints = io.readbytes(#{nbytes}).unpack('#{pack_directive}')" + end + + def create_read_assemble_code(nbits, endian, signed) + nwords = nbits / bits_per_word(nbits) + + idx = (0...nwords).to_a + idx.reverse! if endian == :big + + parts = (0...nwords).collect do |i| + "(ints.at(#{idx[i]}) << #{bits_per_word(nbits) * i})" + end + parts[0].sub!(/ << 0\b/, "") # Remove " << 0" for optimisation + + parts.join(" + ") + end + + def create_to_binary_s_code(nbits, endian, signed) + # special case 8bit integers for speed + return "(val & 0xff).chr" if nbits == 8 + + pack_directive = pack_directive(nbits, endian, signed) + words = val_as_packed_words(nbits, endian, signed) + pack_str = "[#{words}].pack('#{pack_directive}')" + + if need_signed_conversion_code?(nbits, signed) + "#{create_int2uint_code(nbits)} ; #{pack_str}" + else + pack_str + end + end + + def val_as_packed_words(nbits, endian, signed) + nwords = nbits / bits_per_word(nbits) + mask = (1 << bits_per_word(nbits)) - 1 + + vals = (0...nwords).collect { |i| "val >> #{bits_per_word(nbits) * i}" } + vals[0].sub!(/ >> 0\b/, "") # Remove " >> 0" for optimisation + vals.reverse! if (endian == :big) + + vals = vals.collect { |val| "#{val} & #{mask}" } # TODO: "& mask" is needed to work around jruby bug. Remove this line when fixed. + vals.join(",") + end + + def create_int2uint_code(nbits) + "val &= #{(1 << nbits) - 1}" + end + + def create_uint2int_code(nbits) + "(val >= #{1 << (nbits - 1)}) ? val - #{1 << nbits} : val" + end + + def bits_per_word(nbits) + (nbits % 64).zero? ? 64 : + (nbits % 32).zero? ? 32 : + (nbits % 16).zero? ? 16 : + 8 + end + + def pack_directive(nbits, endian, signed) + nwords = nbits / bits_per_word(nbits) + + directives = { 8 => "C", 16 => "S", 32 => "L", 64 => "Q" } + + d = directives[bits_per_word(nbits)] + d << ((endian == :big) ? ">" : "<") unless d == "C" + + if signed == :signed && directives.key?(nbits) + (d * nwords).downcase + else + d * nwords + end + end + + def need_signed_conversion_code?(nbits, signed) + signed == :signed && ![64, 32, 16].include?(nbits) + end + end + end + + + # Unsigned 1 byte integer. + class Uint8 < BinData::BasePrimitive + Int.define_methods(self, 8, :little, :unsigned) + end + + # Signed 1 byte integer. + class Int8 < BinData::BasePrimitive + Int.define_methods(self, 8, :little, :signed) + end + + # Create classes on demand + module IntFactory + def const_missing(name) + mappings = { + /^Uint(\d+)be$/ => [:big, :unsigned], + /^Uint(\d+)le$/ => [:little, :unsigned], + /^Int(\d+)be$/ => [:big, :signed], + /^Int(\d+)le$/ => [:little, :signed], + } + + mappings.each_pair do |regex, args| + if regex =~ name.to_s + nbits = $1.to_i + if nbits > 0 && (nbits % 8).zero? + return Int.define_class(name, nbits, *args) + end + end + end + + super + end + end + BinData.extend IntFactory +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/io.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/io.rb new file mode 100644 index 0000000000000..49a128f8d11c8 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/io.rb @@ -0,0 +1,494 @@ +require 'stringio' + +module BinData + # A wrapper around an IO object. The wrapper provides a consistent + # interface for BinData objects to use when accessing the IO. + module IO + + # Common operations for both Read and Write. + module Common + def initialize(io) + if self.class === io + raise ArgumentError, "io must not be a #{self.class}" + end + + # wrap strings in a StringIO + if io.respond_to?(:to_str) + io = BinData::IO.create_string_io(io.to_str) + end + + @raw_io = io + @buffer_end_points = nil + + extend seekable? ? SeekableStream : UnSeekableStream + stream_init + end + + #------------- + private + + def seekable? + @raw_io.pos + rescue NoMethodError, Errno::ESPIPE, Errno::EPIPE, Errno::EINVAL + nil + end + + def seek(n) + seek_raw(buffer_limited_n(n)) + end + + def buffer_limited_n(n) + if @buffer_end_points + if n.nil? || n > 0 + max = @buffer_end_points[1] - offset + n = max if n.nil? || n > max + else + min = @buffer_end_points[0] - offset + n = min if n < min + end + end + + n + end + + def with_buffer_common(n) + prev = @buffer_end_points + if prev + avail = prev[1] - offset + n = avail if n > avail + end + @buffer_end_points = [offset, offset + n] + begin + yield(*@buffer_end_points) + ensure + @buffer_end_points = prev + end + end + + # Use #seek and #pos on seekable streams + module SeekableStream + # The number of bytes remaining in the input stream. + def num_bytes_remaining + start_mark = @raw_io.pos + @raw_io.seek(0, ::IO::SEEK_END) + end_mark = @raw_io.pos + + if @buffer_end_points + if @buffer_end_points[1] < end_mark + end_mark = @buffer_end_points[1] + end + end + + bytes_remaining = end_mark - start_mark + @raw_io.seek(start_mark, ::IO::SEEK_SET) + + bytes_remaining + end + + # All io calls in +block+ are rolled back after this + # method completes. + def with_readahead + mark = @raw_io.pos + begin + yield + ensure + @raw_io.seek(mark, ::IO::SEEK_SET) + end + end + + #----------- + private + + def stream_init + @initial_pos = @raw_io.pos + end + + def offset_raw + @raw_io.pos - @initial_pos + end + + def seek_raw(n) + @raw_io.seek(n, ::IO::SEEK_CUR) + end + + def read_raw(n) + @raw_io.read(n) + end + + def write_raw(data) + @raw_io.write(data) + end + end + + # Manually keep track of offset for unseekable streams. + module UnSeekableStream + def offset_raw + @offset + end + + # The number of bytes remaining in the input stream. + def num_bytes_remaining + raise IOError, "stream is unseekable" + end + + # All io calls in +block+ are rolled back after this + # method completes. + def with_readahead + mark = @offset + @read_data = "" + @in_readahead = true + + class << self + alias_method :read_raw_without_readahead, :read_raw + alias_method :read_raw, :read_raw_with_readahead + end + + begin + yield + ensure + @offset = mark + @in_readahead = false + end + end + + #----------- + private + + def stream_init + @offset = 0 + end + + def read_raw(n) + data = @raw_io.read(n) + @offset += data.size if data + data + end + + def read_raw_with_readahead(n) + data = "" + + unless @read_data.empty? || @in_readahead + bytes_to_consume = [n, @read_data.length].min + data << @read_data.slice!(0, bytes_to_consume) + n -= bytes_to_consume + + if @read_data.empty? + class << self + alias_method :read_raw, :read_raw_without_readahead + end + end + end + + raw_data = @raw_io.read(n) + data << raw_data if raw_data + + if @in_readahead + @read_data << data + end + + @offset += data.size + + data + end + + def write_raw(data) + @offset += data.size + @raw_io.write(data) + end + + def seek_raw(n) + raise IOError, "stream is unseekable" if n < 0 + + # NOTE: how do we seek on a writable stream? + + # skip over data in 8k blocks + while n > 0 + bytes_to_read = [n, 8192].min + read_raw(bytes_to_read) + n -= bytes_to_read + end + end + end + end + + # Creates a StringIO around +str+. + def self.create_string_io(str = "") + StringIO.new(str.dup.force_encoding(Encoding::BINARY)) + end + + # Create a new IO Read wrapper around +io+. +io+ must provide #read, + # #pos if reading the current stream position and #seek if setting the + # current stream position. If +io+ is a string it will be automatically + # wrapped in an StringIO object. + # + # The IO can handle bitstreams in either big or little endian format. + # + # M byte1 L M byte2 L + # S 76543210 S S fedcba98 S + # B B B B + # + # In big endian format: + # readbits(6), readbits(5) #=> [765432, 10fed] + # + # In little endian format: + # readbits(6), readbits(5) #=> [543210, a9876] + # + class Read + include Common + + def initialize(io) + super(io) + + # bits when reading + @rnbits = 0 + @rval = 0 + @rendian = nil + end + + # Sets a buffer of +n+ bytes on the io stream. Any reading or seeking + # calls inside the +block+ will be contained within this buffer. + def with_buffer(n) + with_buffer_common(n) do + yield + read + end + end + + # Returns the current offset of the io stream. Offset will be rounded + # up when reading bitfields. + def offset + offset_raw + end + + # Seek +n+ bytes from the current position in the io stream. + def seekbytes(n) + reset_read_bits + seek(n) + end + + # Reads exactly +n+ bytes from +io+. + # + # If the data read is nil an EOFError is raised. + # + # If the data read is too short an IOError is raised. + def readbytes(n) + reset_read_bits + read(n) + end + + # Reads all remaining bytes from the stream. + def read_all_bytes + reset_read_bits + read + end + + # Reads exactly +nbits+ bits from the stream. +endian+ specifies whether + # the bits are stored in +:big+ or +:little+ endian format. + def readbits(nbits, endian) + if @rendian != endian + # don't mix bits of differing endian + reset_read_bits + @rendian = endian + end + + if endian == :big + read_big_endian_bits(nbits) + else + read_little_endian_bits(nbits) + end + end + + # Discards any read bits so the stream becomes aligned at the + # next byte boundary. + def reset_read_bits + @rnbits = 0 + @rval = 0 + end + + #--------------- + private + + def read(n = nil) + str = read_raw(buffer_limited_n(n)) + if n + raise EOFError, "End of file reached" if str.nil? + raise IOError, "data truncated" if str.size < n + end + str + end + + def read_big_endian_bits(nbits) + while @rnbits < nbits + accumulate_big_endian_bits + end + + val = (@rval >> (@rnbits - nbits)) & mask(nbits) + @rnbits -= nbits + @rval &= mask(@rnbits) + + val + end + + def accumulate_big_endian_bits + byte = read(1).unpack('C').at(0) & 0xff + @rval = (@rval << 8) | byte + @rnbits += 8 + end + + def read_little_endian_bits(nbits) + while @rnbits < nbits + accumulate_little_endian_bits + end + + val = @rval & mask(nbits) + @rnbits -= nbits + @rval >>= nbits + + val + end + + def accumulate_little_endian_bits + byte = read(1).unpack('C').at(0) & 0xff + @rval = @rval | (byte << @rnbits) + @rnbits += 8 + end + + def mask(nbits) + (1 << nbits) - 1 + end + end + + # Create a new IO Write wrapper around +io+. +io+ must provide #write. + # If +io+ is a string it will be automatically wrapped in an StringIO + # object. + # + # The IO can handle bitstreams in either big or little endian format. + # + # See IO::Read for more information. + class Write + include Common + def initialize(io) + super(io) + + @wnbits = 0 + @wval = 0 + @wendian = nil + end + + # Sets a buffer of +n+ bytes on the io stream. Any writes inside the + # +block+ will be contained within this buffer. If less than +n+ bytes + # are written inside the block, the remainder will be padded with '\0' + # bytes. + def with_buffer(n) + with_buffer_common(n) do |_buf_start, buf_end| + yield + write("\0" * (buf_end - offset)) + end + end + + # Returns the current offset of the io stream. Offset will be rounded + # up when writing bitfields. + def offset + offset_raw + (@wnbits > 0 ? 1 : 0) + end + + # Seek +n+ bytes from the current position in the io stream. + def seekbytes(n) + flushbits + seek(n) + end + + # Writes the given string of bytes to the io stream. + def writebytes(str) + flushbits + write(str) + end + + # Writes +nbits+ bits from +val+ to the stream. +endian+ specifies whether + # the bits are to be stored in +:big+ or +:little+ endian format. + def writebits(val, nbits, endian) + if @wendian != endian + # don't mix bits of differing endian + flushbits + @wendian = endian + end + + clamped_val = val & mask(nbits) + + if endian == :big + write_big_endian_bits(clamped_val, nbits) + else + write_little_endian_bits(clamped_val, nbits) + end + end + + # To be called after all +writebits+ have been applied. + def flushbits + raise "Internal state error nbits = #{@wnbits}" if @wnbits >= 8 + + if @wnbits > 0 + writebits(0, 8 - @wnbits, @wendian) + end + end + alias flush flushbits + + #--------------- + private + + def write(data) + n = buffer_limited_n(data.size) + if n < data.size + data = data[0, n] + end + + write_raw(data) + end + + def write_big_endian_bits(val, nbits) + while nbits > 0 + bits_req = 8 - @wnbits + if nbits >= bits_req + msb_bits = (val >> (nbits - bits_req)) & mask(bits_req) + nbits -= bits_req + val &= mask(nbits) + + @wval = (@wval << bits_req) | msb_bits + write(@wval.chr) + + @wval = 0 + @wnbits = 0 + else + @wval = (@wval << nbits) | val + @wnbits += nbits + nbits = 0 + end + end + end + + def write_little_endian_bits(val, nbits) + while nbits > 0 + bits_req = 8 - @wnbits + if nbits >= bits_req + lsb_bits = val & mask(bits_req) + nbits -= bits_req + val >>= bits_req + + @wval = @wval | (lsb_bits << @wnbits) + write(@wval.chr) + + @wval = 0 + @wnbits = 0 + else + @wval = @wval | (val << @wnbits) + @wnbits += nbits + nbits = 0 + end + end + end + + def mask(nbits) + (1 << nbits) - 1 + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/lazy.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/lazy.rb new file mode 100644 index 0000000000000..0726072022b0b --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/lazy.rb @@ -0,0 +1,109 @@ +module BinData + # A LazyEvaluator is bound to a data object. The evaluator will evaluate + # lambdas in the context of this data object. These lambdas + # are those that are passed to data objects as parameters, e.g.: + # + # BinData::String.new(value: -> { %w(a test message).join(" ") }) + # + # As a shortcut, :foo is the equivalent of lambda { foo }. + # + # When evaluating lambdas, unknown methods are resolved in the context of the + # parent of the bound data object. Resolution is attempted firstly as keys + # in #parameters, and secondly as methods in this parent. This + # resolution propagates up the chain of parent data objects. + # + # An evaluation will recurse until it returns a result that is not + # a lambda or a symbol. + # + # This resolution process makes the lambda easier to read as we just write + # field instead of obj.field. + class LazyEvaluator + + # Creates a new evaluator. All lazy evaluation is performed in the + # context of +obj+. + def initialize(obj) + @obj = obj + end + + def lazy_eval(val, overrides = nil) + @overrides = overrides if overrides + if val.is_a? Symbol + __send__(val) + elsif callable?(val) + instance_exec(&val) + else + val + end + end + + # Returns a LazyEvaluator for the parent of this data object. + def parent + if @obj.parent + @obj.parent.lazy_evaluator + else + nil + end + end + + # Returns the index of this data object inside it's nearest container + # array. + def index + return @overrides[:index] if defined?(@overrides) && @overrides.key?(:index) + + child = @obj + parent = @obj.parent + while parent + if parent.respond_to?(:find_index_of) + return parent.find_index_of(child) + end + child = parent + parent = parent.parent + end + raise NoMethodError, "no index found" + end + + def method_missing(symbol, *args) + return @overrides[symbol] if defined?(@overrides) && @overrides.key?(symbol) + + if @obj.parent + eval_symbol_in_parent_context(symbol, args) + else + super + end + end + + #--------------- + private + + def eval_symbol_in_parent_context(symbol, args) + result = resolve_symbol_in_parent_context(symbol, args) + recursively_eval(result, args) + end + + def resolve_symbol_in_parent_context(symbol, args) + obj_parent = @obj.parent + + if obj_parent.has_parameter?(symbol) + obj_parent.get_parameter(symbol) + elsif obj_parent.safe_respond_to?(symbol, true) + obj_parent.__send__(symbol, *args) + else + symbol + end + end + + def recursively_eval(val, args) + if val.is_a?(Symbol) + parent.__send__(val, *args) + elsif callable?(val) + parent.instance_exec(&val) + else + val + end + end + + def callable?(obj) + Proc === obj || Method === obj || UnboundMethod === obj + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/name.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/name.rb new file mode 100644 index 0000000000000..bd22b50312f9d --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/name.rb @@ -0,0 +1,28 @@ +module BinData + # == Parameters + # + # Parameters may be provided at initialisation to control the behaviour of + # an object. These parameters are: + # + # :name:: The name that this object can be referred to may be + # set explicitly. This is only useful when dynamically + # generating types. + #
+  #                    BinData::Struct.new(name: :my_struct, fields: ...)
+  #                    array = BinData::Array.new(type: :my_struct)
+  #                  
+ module RegisterNamePlugin + + def self.included(base) #:nodoc: + # The registered name may be provided explicitly. + base.optional_parameter :name + end + + def initialize_shared_instance + if has_parameter?(:name) + RegisteredClasses.register(get_parameter(:name), self) + end + super + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/offset.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/offset.rb new file mode 100644 index 0000000000000..7b9a61e658c6e --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/offset.rb @@ -0,0 +1,94 @@ +module BinData + # WARNING: THIS IS UNSUPPORTED!! + # + # This was a (failed) experimental feature that allowed seeking within the + # input stream. It remains here for backwards compatability for the few + # people that used it. + # + # The official way to skip around the stream is to use BinData::Skip with + # the `:to_abs_offset` parameter. + # + # == Parameters + # + # Parameters may be provided at initialisation to control the behaviour of + # an object. These parameters are: + # + # [:check_offset] Raise an error if the current IO offset doesn't + # meet this criteria. A boolean return indicates + # success or failure. Any other return is compared + # to the current offset. The variable +offset+ + # is made available to any lambda assigned to + # this parameter. This parameter is only checked + # before reading. + # [:adjust_offset] Ensures that the current IO offset is at this + # position before reading. This is like + # :check_offset, except that it will + # adjust the IO offset instead of raising an error. + module CheckOrAdjustOffsetPlugin + + def self.included(base) #:nodoc: + base.optional_parameters :check_offset, :adjust_offset + base.mutually_exclusive_parameters :check_offset, :adjust_offset + end + + def initialize_shared_instance + extend CheckOffsetMixin if has_parameter?(:check_offset) + extend AdjustOffsetMixin if has_parameter?(:adjust_offset) + super + end + + module CheckOffsetMixin + def do_read(io) #:nodoc: + check_offset(io) + super(io) + end + + #--------------- + private + + def check_offset(io) + actual_offset = io.offset + expected = eval_parameter(:check_offset, offset: actual_offset) + + if !expected + raise ValidityError, "offset not as expected for #{debug_name}" + elsif actual_offset != expected && expected != true + raise ValidityError, + "offset is '#{actual_offset}' but " + + "expected '#{expected}' for #{debug_name}" + end + end + end + + module AdjustOffsetMixin + def do_read(io) #:nodoc: + adjust_offset(io) + super(io) + end + + #--------------- + private + + def adjust_offset(io) + actual_offset = io.offset + expected = eval_parameter(:adjust_offset) + if actual_offset != expected + begin + seek = expected - actual_offset + io.seekbytes(seek) + warn "adjusting stream position by #{seek} bytes" if $VERBOSE + rescue + raise ValidityError, + "offset is '#{actual_offset}' but couldn't seek to " + + "expected '#{expected}' for #{debug_name}" + end + end + end + end + end + + # Add these offset options to Base + class Base + include CheckOrAdjustOffsetPlugin + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/params.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/params.rb new file mode 100644 index 0000000000000..80112483c986b --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/params.rb @@ -0,0 +1,128 @@ +require 'bindata/lazy' + +module BinData + module AcceptedParametersPlugin + # Mandatory parameters must be present when instantiating a data object. + def mandatory_parameters(*args) + accepted_parameters.mandatory(*args) + end + + # Optional parameters may be present when instantiating a data object. + def optional_parameters(*args) + accepted_parameters.optional(*args) + end + + # Default parameters can be overridden when instantiating a data object. + def default_parameters(*args) + accepted_parameters.default(*args) + end + + # Mutually exclusive parameters may not all be present when + # instantiating a data object. + def mutually_exclusive_parameters(*args) + accepted_parameters.mutually_exclusive(*args) + end + + alias mandatory_parameter mandatory_parameters + alias optional_parameter optional_parameters + alias default_parameter default_parameters + + def accepted_parameters #:nodoc: + @accepted_parameters ||= begin + ancestor_params = superclass.respond_to?(:accepted_parameters) ? + superclass.accepted_parameters : nil + AcceptedParameters.new(ancestor_params) + end + end + + # BinData objects accept parameters when initializing. AcceptedParameters + # allow a BinData class to declaratively identify accepted parameters as + # mandatory, optional, default or mutually exclusive. + class AcceptedParameters + def initialize(ancestor_parameters = nil) + if ancestor_parameters + @mandatory = ancestor_parameters.mandatory.dup + @optional = ancestor_parameters.optional.dup + @default = ancestor_parameters.default.dup + @mutually_exclusive = ancestor_parameters.mutually_exclusive.dup + else + @mandatory = [] + @optional = [] + @default = Hash.new + @mutually_exclusive = [] + end + end + + def mandatory(*args) + unless args.empty? + @mandatory.concat(to_syms(args)) + @mandatory.uniq! + end + @mandatory + end + + def optional(*args) + unless args.empty? + @optional.concat(to_syms(args)) + @optional.uniq! + end + @optional + end + + def default(args = nil) + if args + to_syms(args.keys) # call for side effect of validating names + args.each_pair do |param, value| + @default[param.to_sym] = value + end + end + @default + end + + def mutually_exclusive(*args) + arg1 = args.shift + until args.empty? + args.each do |arg2| + @mutually_exclusive.push([arg1.to_sym, arg2.to_sym]) + @mutually_exclusive.uniq! + end + arg1 = args.shift + end + @mutually_exclusive + end + + def all + (@mandatory + @optional + @default.keys).uniq + end + + #--------------- + private + + def to_syms(args) + syms = args.collect(&:to_sym) + ensure_valid_names(syms) + syms + end + + def ensure_valid_names(names) + invalid_names = self.class.invalid_parameter_names + names.each do |name| + if invalid_names.include?(name) + raise NameError.new("Rename parameter '#{name}' " \ + "as it shadows an existing method.", name) + end + end + end + + def self.invalid_parameter_names + @invalid_names ||= begin + all_names = LazyEvaluator.instance_methods(true) + Kernel.methods + allowed_names = [:name, :type] + invalid_names = (all_names - allowed_names).uniq + + Hash[*invalid_names.collect { |key| [key.to_sym, true] }.flatten] + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/primitive.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/primitive.rb new file mode 100644 index 0000000000000..9b9bd8d41d5bd --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/primitive.rb @@ -0,0 +1,143 @@ +require 'bindata/base_primitive' +require 'bindata/dsl' +require 'bindata/struct' + +module BinData + # A Primitive is a declarative way to define a new BinData data type. + # The data type must contain a primitive value only, i.e numbers or strings. + # For new data types that contain multiple values see BinData::Record. + # + # To define a new data type, set fields as if for Record and add a + # #get and #set method to extract / convert the data between the fields + # and the #value of the object. + # + # require 'bindata' + # + # class PascalString < BinData::Primitive + # uint8 :len, value: -> { data.length } + # string :data, read_length: :len + # + # def get + # self.data + # end + # + # def set(v) + # self.data = v + # end + # end + # + # ps = PascalString.new(initial_value: "hello") + # ps.to_binary_s #=> "\005hello" + # ps.read("\003abcde") + # ps #=> "abc" + # + # # Unsigned 24 bit big endian integer + # class Uint24be < BinData::Primitive + # uint8 :byte1 + # uint8 :byte2 + # uint8 :byte3 + # + # def get + # (self.byte1 << 16) | (self.byte2 << 8) | self.byte3 + # end + # + # def set(v) + # v = 0 if v < 0 + # v = 0xffffff if v > 0xffffff + # + # self.byte1 = (v >> 16) & 0xff + # self.byte2 = (v >> 8) & 0xff + # self.byte3 = v & 0xff + # end + # end + # + # u24 = Uint24be.new + # u24.read("\x12\x34\x56") + # "0x%x" % u24 #=> 0x123456 + # + # == Parameters + # + # Primitive objects accept all the parameters that BinData::BasePrimitive do. + # + class Primitive < BasePrimitive + extend DSLMixin + + unregister_self + dsl_parser :primitive + arg_processor :primitive + + mandatory_parameter :struct_params + + def initialize_instance + super + @struct = BinData::Struct.new(get_parameter(:struct_params), self) + end + + def respond_to?(symbol, include_private = false) #:nodoc: + @struct.respond_to?(symbol, include_private) || super + end + + def method_missing(symbol, *args, &block) #:nodoc: + if @struct.respond_to?(symbol) + @struct.__send__(symbol, *args, &block) + else + super + end + end + + def assign(val) + super(val) + set(_value) + @value = get + end + + def debug_name_of(child) #:nodoc: + debug_name + "-internal-" + end + + def do_write(io) + set(_value) + @struct.do_write(io) + end + + def do_num_bytes + set(_value) + @struct.do_num_bytes + end + + #--------------- + private + + def sensible_default + get + end + + def read_and_return_value(io) + @struct.do_read(io) + get + end + + ########################################################################### + # To be implemented by subclasses + + # Extracts the value for this data object from the fields of the + # internal struct. + def get + raise NotImplementedError + end + + # Sets the fields of the internal struct to represent +v+. + def set(v) + raise NotImplementedError + end + + # To be implemented by subclasses + ########################################################################### + end + + class PrimitiveArgProcessor < BaseArgProcessor + def sanitize_parameters!(obj_class, params) + params[:struct_params] = params.create_sanitized_params(obj_class.dsl_params, BinData::Struct) + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/record.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/record.rb new file mode 100644 index 0000000000000..b011cf5e1c8dd --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/record.rb @@ -0,0 +1,23 @@ +require 'bindata/dsl' +require 'bindata/struct' + +module BinData + # A Record is a declarative wrapper around Struct. + # + # See +Struct+ for more info. + class Record < BinData::Struct + extend DSLMixin + + unregister_self + dsl_parser :struct + arg_processor :record + end + + class RecordArgProcessor < StructArgProcessor + include MultiFieldArgSeparator + + def sanitize_parameters!(obj_class, params) + super(obj_class, params.merge!(obj_class.dsl_params)) + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/registry.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/registry.rb new file mode 100644 index 0000000000000..fc47740bd5594 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/registry.rb @@ -0,0 +1,134 @@ +module BinData + + class UnRegisteredTypeError < StandardError ; end + + # This registry contains a register of name -> class mappings. + # + # Numerics (integers and floating point numbers) have an endian property as + # part of their name (e.g. int32be, float_le). + # + # Classes can be looked up based on their full name or an abbreviated +name+ + # with +hints+. + # + # There are two hints supported, :endian and :search_prefix. + # + # #lookup("int32", { endian: :big }) will return Int32Be. + # + # #lookup("my_type", { search_prefix: :ns }) will return NsMyType. + # + # Names are stored in under_score_style, not camelCase. + class Registry + + def initialize + @registry = {} + end + + def register(name, class_to_register) + return if name.nil? || class_to_register.nil? + + formatted_name = underscore_name(name) + warn_if_name_is_already_registered(formatted_name, class_to_register) + + @registry[formatted_name] = class_to_register + end + + def unregister(name) + @registry.delete(underscore_name(name)) + end + + def lookup(name, hints = {}) + the_class = @registry[normalize_name(name, hints)] + if the_class + the_class + elsif @registry[normalize_name(name, hints.merge(endian: :big))] + raise(UnRegisteredTypeError, "#{name}, do you need to specify endian?") + else + raise(UnRegisteredTypeError, name) + end + end + + # Convert CamelCase +name+ to underscore style. + def underscore_name(name) + name. + to_s. + sub(/.*::/, ""). + gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2'). + gsub(/([a-z\d])([A-Z])/, '\1_\2'). + tr("-", "_"). + downcase + end + + #--------------- + private + + def normalize_name(name, hints) + name = underscore_name(name) + + if !registered?(name) + search_prefix = [""].concat(Array(hints[:search_prefix])) + search_prefix.each do |prefix| + nwp = name_with_prefix(name, prefix) + if registered?(nwp) + name = nwp + break + end + + nwe = name_with_endian(nwp, hints[:endian]) + if registered?(nwe) + name = nwe + break + end + end + end + + name + end + + def name_with_prefix(name, prefix) + prefix = prefix.to_s.chomp("_") + if prefix == "" + name + else + "#{prefix}_#{name}" + end + end + + def name_with_endian(name, endian) + return name if endian.nil? + + suffix = (endian == :little) ? "le" : "be" + if /^u?int\d+$/ =~ name + name + suffix + else + name + "_" + suffix + end + end + + def registered?(name) + register_dynamic_class(name) unless @registry.key?(name) + + @registry.key?(name) + end + + def register_dynamic_class(name) + if /^u?int\d+(le|be)$/ =~ name || /^s?bit\d+(le)?$/ =~ name + class_name = name.gsub(/(?:^|_)(.)/) { $1.upcase } + begin + BinData.const_get(class_name) + rescue NameError + end + end + end + + def warn_if_name_is_already_registered(name, class_to_register) + prev_class = @registry[name] + if $VERBOSE && prev_class && prev_class != class_to_register + warn "warning: replacing registered class #{prev_class} " \ + "with #{class_to_register}" + end + end + end + + # A singleton registry of all registered classes. + RegisteredClasses = Registry.new +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/rest.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/rest.rb new file mode 100644 index 0000000000000..cdc104459c568 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/rest.rb @@ -0,0 +1,34 @@ +require "bindata/base_primitive" + +module BinData + # Rest will consume the input stream from the current position to the end of + # the stream. This will mainly be useful for debugging and developing. + # + # require 'bindata' + # + # class A < BinData::Record + # string :a, read_length: 5 + # rest :rest + # end + # + # obj = A.read("abcdefghij") + # obj.a #=> "abcde" + # obj.rest #=" "fghij" + # + class Rest < BinData::BasePrimitive + #--------------- + private + + def value_to_binary_string(val) + val + end + + def read_and_return_value(io) + io.read_all_bytes + end + + def sensible_default + "" + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/sanitize.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/sanitize.rb new file mode 100644 index 0000000000000..7325b206b0c47 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/sanitize.rb @@ -0,0 +1,372 @@ +require 'bindata/registry' + +module BinData + + # Subclasses of this are sanitized + class SanitizedParameter; end + + class SanitizedPrototype < SanitizedParameter + def initialize(obj_type, obj_params, hints) + raw_hints = hints.dup + if raw_hints[:endian].respond_to?(:endian) + raw_hints[:endian] = raw_hints[:endian].endian + end + obj_params ||= {} + + if BinData::Base === obj_type + obj_class = obj_type + else + obj_class = RegisteredClasses.lookup(obj_type, raw_hints) + end + + if BinData::Base === obj_class + @factory = obj_class + else + @obj_class = obj_class + @obj_params = SanitizedParameters.new(obj_params, @obj_class, hints) + end + end + + def has_parameter?(param) + if defined? @factory + @factory.has_parameter?(param) + else + @obj_params.has_parameter?(param) + end + end + + def instantiate(value = nil, parent = nil) + @factory ||= @obj_class.new(@obj_params) + + @factory.new(value, parent) + end + end + #---------------------------------------------------------------------------- + + class SanitizedField < SanitizedParameter + def initialize(name, field_type, field_params, hints) + @name = name + @prototype = SanitizedPrototype.new(field_type, field_params, hints) + end + + attr_reader :prototype + + def name_as_sym + @name.nil? ? nil : @name.to_sym + end + + def name + @name + end + + def has_parameter?(param) + @prototype.has_parameter?(param) + end + + def instantiate(value = nil, parent = nil) + @prototype.instantiate(value, parent) + end + end + #---------------------------------------------------------------------------- + + class SanitizedFields < SanitizedParameter + include Enumerable + + def initialize(hints, base_fields = nil) + @hints = hints + if base_fields + @fields = base_fields.raw_fields + else + @fields = [] + end + end + + def add_field(type, name, params) + name = nil if name == "" + + @fields << SanitizedField.new(name, type, params, @hints) + end + + def raw_fields + @fields.dup + end + + def [](idx) + @fields[idx] + end + + def empty? + @fields.empty? + end + + def length + @fields.length + end + + def each(&block) + @fields.each(&block) + end + + def field_names + @fields.collect(&:name_as_sym) + end + + def field_name?(name) + @fields.detect { |f| f.name_as_sym == name.to_sym } + end + + def all_field_names_blank? + @fields.all? { |f| f.name.nil? } + end + + def no_field_names_blank? + @fields.all? { |f| f.name != nil } + end + + def any_field_has_parameter?(parameter) + @fields.any? { |f| f.has_parameter?(parameter) } + end + end + #---------------------------------------------------------------------------- + + class SanitizedChoices < SanitizedParameter + def initialize(choices, hints) + @choices = {} + choices.each_pair do |key, val| + if SanitizedParameter === val + prototype = val + else + type, param = val + prototype = SanitizedPrototype.new(type, param, hints) + end + + if key == :default + @choices.default = prototype + else + @choices[key] = prototype + end + end + end + + def [](key) + @choices[key] + end + end + #---------------------------------------------------------------------------- + + class SanitizedBigEndian < SanitizedParameter + def endian + :big + end + end + + class SanitizedLittleEndian < SanitizedParameter + def endian + :little + end + end + #---------------------------------------------------------------------------- + + # BinData objects are instantiated with parameters to determine their + # behaviour. These parameters must be sanitized to ensure their values + # are valid. When instantiating many objects with identical parameters, + # such as an array of records, there is much duplicated sanitizing. + # + # The purpose of the sanitizing code is to eliminate the duplicated + # validation. + # + # SanitizedParameters is a hash-like collection of parameters. Its purpose + # is to recursively sanitize the parameters of an entire BinData object chain + # at a single time. + class SanitizedParameters < Hash + + # Memoized constants + BIG_ENDIAN = SanitizedBigEndian.new + LITTLE_ENDIAN = SanitizedLittleEndian.new + + class << self + def sanitize(parameters, the_class) + if SanitizedParameters === parameters + parameters + else + SanitizedParameters.new(parameters, the_class, {}) + end + end + end + + def initialize(parameters, the_class, hints) + parameters.each_pair { |key, value| self[key.to_sym] = value } + + @the_class = the_class + + if hints[:endian] + self[:endian] ||= hints[:endian] + end + + if hints[:search_prefix] && !hints[:search_prefix].empty? + self[:search_prefix] = Array(self[:search_prefix]).concat(Array(hints[:search_prefix])) + end + + sanitize! + end + + alias_method :has_parameter?, :key? + + def has_at_least_one_of?(*keys) + keys.each do |key| + return true if has_parameter?(key) + end + + false + end + + def warn_replacement_parameter(bad_key, suggested_key) + if has_parameter?(bad_key) + Kernel.warn ":#{bad_key} is not used with #{@the_class}. " \ + "You probably want to change this to :#{suggested_key}" + end + end + +# def warn_renamed_parameter(old_key, new_key) +# val = delete(old_key) +# if val +# self[new_key] = val +# Kernel.warn ":#{old_key} has been renamed to :#{new_key} in #{@the_class}. " \ +# "Using :#{old_key} is now deprecated and will be removed in the future" +# end +# end + + def must_be_integer(*keys) + keys.each do |key| + if has_parameter?(key) + parameter = self[key] + unless Symbol === parameter || + parameter.respond_to?(:arity) || + parameter.respond_to?(:to_int) + raise ArgumentError, "parameter '#{key}' in #{@the_class} must " \ + "evaluate to an integer, got #{parameter.class}" + end + end + end + end + + def rename_parameter(old_key, new_key) + if has_parameter?(old_key) + self[new_key] = delete(old_key) + end + end + + def sanitize_object_prototype(key) + sanitize(key) { |obj_type, obj_params| create_sanitized_object_prototype(obj_type, obj_params) } + end + + def sanitize_fields(key, &block) + sanitize(key) do |fields| + sanitized_fields = create_sanitized_fields + yield(fields, sanitized_fields) + sanitized_fields + end + end + + def sanitize_choices(key, &block) + sanitize(key) do |obj| + create_sanitized_choices(yield(obj)) + end + end + + def sanitize_endian(key) + sanitize(key) { |endian| create_sanitized_endian(endian) } + end + + def sanitize(key, &block) + if needs_sanitizing?(key) + self[key] = yield(self[key]) + end + end + + def create_sanitized_params(params, the_class) + SanitizedParameters.new(params, the_class, hints) + end + + def hints + { endian: self[:endian], search_prefix: self[:search_prefix] } + end + + #--------------- + private + + def sanitize! + ensure_no_nil_values + merge_default_parameters! + + @the_class.arg_processor.sanitize_parameters!(@the_class, self) + + ensure_mandatory_parameters_exist + ensure_mutual_exclusion_of_parameters + end + + def needs_sanitizing?(key) + has_key?(key) && ! self[key].is_a?(SanitizedParameter) + end + + def ensure_no_nil_values + each do |key, value| + if value.nil? + raise ArgumentError, + "parameter '#{key}' has nil value in #{@the_class}" + end + end + end + + def merge_default_parameters! + @the_class.default_parameters.each do |key, value| + self[key] = value unless has_key?(key) + end + end + + def ensure_mandatory_parameters_exist + @the_class.mandatory_parameters.each do |key| + unless has_parameter?(key) + raise ArgumentError, + "parameter '#{key}' must be specified in #{@the_class}" + end + end + end + + def ensure_mutual_exclusion_of_parameters + return if length < 2 + + @the_class.mutually_exclusive_parameters.each do |key1, key2| + if has_parameter?(key1) && has_parameter?(key2) + raise ArgumentError, "params '#{key1}' and '#{key2}' " \ + "are mutually exclusive in #{@the_class}" + end + end + end + + def create_sanitized_endian(endian) + if endian == :big + BIG_ENDIAN + elsif endian == :little + LITTLE_ENDIAN + elsif endian == :big_and_little + raise ArgumentError, "endian: :big or endian: :little is required" + else + raise ArgumentError, "unknown value for endian '#{endian}'" + end + end + + def create_sanitized_choices(choices) + SanitizedChoices.new(choices, hints) + end + + def create_sanitized_fields + SanitizedFields.new(hints) + end + + def create_sanitized_object_prototype(obj_type, obj_params) + SanitizedPrototype.new(obj_type, obj_params, hints) + end + end + #---------------------------------------------------------------------------- +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/skip.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/skip.rb new file mode 100644 index 0000000000000..40d4fe940af67 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/skip.rb @@ -0,0 +1,133 @@ +require "bindata/base_primitive" + +module BinData + # Skip will skip over bytes from the input stream. If the stream is not + # seekable, then the bytes are consumed and discarded. + # + # When writing, skip will write the appropriate number of zero bytes. + # + # require 'bindata' + # + # class A < BinData::Record + # skip length: 5 + # string :a, read_length: 5 + # end + # + # obj = A.read("abcdefghij") + # obj.a #=> "fghij" + # + # + # class B < BinData::Record + # skip until_valid: [:string, {read_length: 2, assert: "ef"} ] + # string :b, read_length: 5 + # end + # + # obj = B.read("abcdefghij") + # obj.b #=> "efghi" + # + # + # == Parameters + # + # Skip objects accept all the params that BinData::BasePrimitive + # does, as well as the following: + # + # :length:: The number of bytes to skip. + # :to_abs_offset:: Skips to the given absolute offset. + # :until_valid:: Skips untils a given byte pattern is matched. + # This parameter contains a type that will raise + # a BinData::ValidityError unless an acceptable byte + # sequence is found. The type is represented by a + # Symbol, or if the type is to have params # + # passed to it, then it should be provided as # + # [type_symbol, hash_params]. + # + class Skip < BinData::BasePrimitive + arg_processor :skip + + optional_parameters :length, :to_abs_offset, :until_valid + mutually_exclusive_parameters :length, :to_abs_offset, :until_valid + + def initialize_shared_instance + extend SkipLengthPlugin if has_parameter?(:length) + extend SkipToAbsOffsetPlugin if has_parameter?(:to_abs_offset) + extend SkipUntilValidPlugin if has_parameter?(:until_valid) + super + end + + #--------------- + private + + def value_to_binary_string(val) + len = skip_length + if len < 0 + raise ValidityError, "#{debug_name} attempted to seek backwards by #{len.abs} bytes" + end + + "\000" * skip_length + end + + def read_and_return_value(io) + len = skip_length + if len < 0 + raise ValidityError, "#{debug_name} attempted to seek backwards by #{len.abs} bytes" + end + + io.seekbytes(len) + "" + end + + def sensible_default + "" + end + end + + class SkipArgProcessor < BaseArgProcessor + def sanitize_parameters!(obj_class, params) + unless params.has_at_least_one_of?(:length, :to_abs_offset, :until_valid) + raise ArgumentError, + "#{obj_class} requires either :length, :to_abs_offset or :until_valid" + end + params.must_be_integer(:to_abs_offset, :length) + params.sanitize_object_prototype(:until_valid) + end + end + + # Logic for the :length parameter + module SkipLengthPlugin + def skip_length + eval_parameter(:length) + end + end + + # Logic for the :to_abs_offset parameter + module SkipToAbsOffsetPlugin + def skip_length + eval_parameter(:to_abs_offset) - abs_offset + end + end + + # Logic for the :until_valid parameter + module SkipUntilValidPlugin + def skip_length + # no skipping when writing + 0 + end + + def read_and_return_value(io) + prototype = get_parameter(:until_valid) + validator = prototype.instantiate(nil, self) + + valid = false + until valid + begin + io.with_readahead do + validator.read(io) + valid = true + end + rescue ValidityError + io.readbytes(1) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/string.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/string.rb new file mode 100644 index 0000000000000..cf744ae2dfad3 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/string.rb @@ -0,0 +1,153 @@ +require "bindata/base_primitive" + +module BinData + # A String is a sequence of bytes. This is the same as strings in Ruby 1.8. + # The issue of character encoding is ignored by this class. + # + # require 'bindata' + # + # data = "abcdefghij" + # + # obj = BinData::String.new(read_length: 5) + # obj.read(data) + # obj #=> "abcde" + # + # obj = BinData::String.new(length: 6) + # obj.read(data) + # obj #=> "abcdef" + # obj.assign("abcdefghij") + # obj #=> "abcdef" + # obj.assign("abcd") + # obj #=> "abcd\000\000" + # + # obj = BinData::String.new(length: 6, trim_padding: true) + # obj.assign("abcd") + # obj #=> "abcd" + # obj.to_binary_s #=> "abcd\000\000" + # + # obj = BinData::String.new(length: 6, pad_byte: 'A') + # obj.assign("abcd") + # obj #=> "abcdAA" + # obj.to_binary_s #=> "abcdAA" + # + # == Parameters + # + # String objects accept all the params that BinData::BasePrimitive + # does, as well as the following: + # + # :read_length:: The length in bytes to use when reading a value. + # :length:: The fixed length of the string. If a shorter + # string is set, it will be padded to this length. + # :pad_byte:: The byte to use when padding a string to a + # set length. Valid values are Integers and + # Strings of length 1. "\0" is the default. + # :pad_front:: Signifies that the padding occurs at the front + # of the string rather than the end. Default + # is false. + # :trim_padding:: Boolean, default false. If set, #value will + # return the value with all pad_bytes trimmed + # from the end of the string. The value will + # not be trimmed when writing. + class String < BinData::BasePrimitive + arg_processor :string + + optional_parameters :read_length, :length, :trim_padding, :pad_front, :pad_left + default_parameters pad_byte: "\0" + mutually_exclusive_parameters :read_length, :length + mutually_exclusive_parameters :length, :value + + def initialize_shared_instance + if (has_parameter?(:value) || has_parameter?(:asserted_value)) && + !has_parameter?(:read_length) + extend WarnNoReadLengthPlugin + end + super + end + + def assign(val) + super(binary_string(val)) + end + + def snapshot + # override to trim padding + snap = super + snap = clamp_to_length(snap) + + if get_parameter(:trim_padding) + trim_padding(snap) + else + snap + end + end + + #--------------- + private + + def clamp_to_length(str) + str = binary_string(str) + + len = eval_parameter(:length) || str.length + if str.length == len + str + elsif str.length > len + str.slice(0, len) + else + padding = (eval_parameter(:pad_byte) * (len - str.length)) + if get_parameter(:pad_front) + padding + str + else + str + padding + end + end + end + + def trim_padding(str) + if get_parameter(:pad_front) + str.sub(/\A#{eval_parameter(:pad_byte)}*/, "") + else + str.sub(/#{eval_parameter(:pad_byte)}*\z/, "") + end + end + + def value_to_binary_string(val) + clamp_to_length(val) + end + + def read_and_return_value(io) + len = eval_parameter(:read_length) || eval_parameter(:length) || 0 + io.readbytes(len) + end + + def sensible_default + "" + end + end + + class StringArgProcessor < BaseArgProcessor + def sanitize_parameters!(obj_class, params) + params.warn_replacement_parameter(:initial_length, :read_length) + params.must_be_integer(:read_length, :length) + params.rename_parameter(:pad_left, :pad_front) + params.sanitize(:pad_byte) { |byte| sanitized_pad_byte(byte) } + end + + #------------- + private + + def sanitized_pad_byte(byte) + pad_byte = byte.is_a?(Integer) ? byte.chr : byte.to_s + if pad_byte.bytesize > 1 + raise ArgumentError, ":pad_byte must not contain more than 1 byte" + end + pad_byte + end + end + + # Warns when reading if :value && no :read_length + module WarnNoReadLengthPlugin + def read_and_return_value(io) + warn "#{debug_name} does not have a :read_length parameter - returning empty string" + "" + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/stringz.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/stringz.rb new file mode 100644 index 0000000000000..74e8814f9b290 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/stringz.rb @@ -0,0 +1,96 @@ +require "bindata/base_primitive" + +module BinData + # A BinData::Stringz object is a container for a zero ("\0") terminated + # string. + # + # For convenience, the zero terminator is not necessary when setting the + # value. Likewise, the returned value will not be zero terminated. + # + # require 'bindata' + # + # data = "abcd\x00efgh" + # + # obj = BinData::Stringz.new + # obj.read(data) + # obj.snapshot #=> "abcd" + # obj.num_bytes #=> 5 + # obj.to_binary_s #=> "abcd\000" + # + # == Parameters + # + # Stringz objects accept all the params that BinData::BasePrimitive + # does, as well as the following: + # + # :max_length:: The maximum length of the string including the zero + # byte. + class Stringz < BinData::BasePrimitive + + optional_parameters :max_length + + def assign(val) + super(binary_string(val)) + end + + def snapshot + # override to always remove trailing zero bytes + result = super + trim_and_zero_terminate(result).chomp("\0") + end + + #--------------- + private + + def value_to_binary_string(val) + trim_and_zero_terminate(val) + end + + def read_and_return_value(io) + max_length = eval_parameter(:max_length) + str = "" + i = 0 + ch = nil + + # read until zero byte or we have read in the max number of bytes + while ch != "\0" && i != max_length + ch = io.readbytes(1) + str << ch + i += 1 + end + + trim_and_zero_terminate(str) + end + + def sensible_default + "" + end + + def trim_and_zero_terminate(str) + result = binary_string(str) + truncate_after_first_zero_byte!(result) + trim_to!(result, eval_parameter(:max_length)) + append_zero_byte_if_needed!(result) + result + end + + def truncate_after_first_zero_byte!(str) + str.sub!(/([^\0]*\0).*/, '\1') + end + + def trim_to!(str, max_length = nil) + if max_length + max_length = 1 if max_length < 1 + str.slice!(max_length) + if str.length == max_length && str[-1, 1] != "\0" + str[-1, 1] = "\0" + end + end + end + + def append_zero_byte_if_needed!(str) + if str.length == 0 || str[-1, 1] != "\0" + str << "\0" + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/struct.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/struct.rb new file mode 100644 index 0000000000000..a34ec85701920 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/struct.rb @@ -0,0 +1,415 @@ +require 'bindata/base' + +module BinData + + class Base + optional_parameter :onlyif, :byte_align # Used by Struct + end + + # A Struct is an ordered collection of named data objects. + # + # require 'bindata' + # + # class Tuple < BinData::Record + # int8 :x + # int8 :y + # int8 :z + # end + # + # obj = BinData::Struct.new(hide: :a, + # fields: [ [:int32le, :a], + # [:int16le, :b], + # [:tuple, :s] ]) + # obj.field_names =># [:b, :s] + # + # + # == Parameters + # + # Parameters may be provided at initialisation to control the behaviour of + # an object. These params are: + # + # :fields:: An array specifying the fields for this struct. + # Each element of the array is of the form [type, name, + # params]. Type is a symbol representing a registered + # type. Name is the name of this field. Params is an + # optional hash of parameters to pass to this field + # when instantiating it. If name is "" or nil, then + # that field is anonymous and behaves as a hidden field. + # :hide:: A list of the names of fields that are to be hidden + # from the outside world. Hidden fields don't appear + # in #snapshot or #field_names but are still accessible + # by name. + # :endian:: Either :little or :big. This specifies the default + # endian of any numerics in this struct, or in any + # nested data objects. + # :search_prefix:: Allows abbreviated type names. If a type is + # unrecognised, then each prefix is applied until + # a match is found. + # + # == Field Parameters + # + # Fields may have have extra parameters as listed below: + # + # [:onlyif] Used to indicate a data object is optional. + # if +false+, this object will not be included in any + # calls to #read, #write, #num_bytes or #snapshot. + # [:byte_align] This field's rel_offset must be a multiple of + # :byte_align. + class Struct < BinData::Base + arg_processor :struct + + mandatory_parameter :fields + optional_parameters :endian, :search_prefix, :hide + + # These reserved words may not be used as field names + RESERVED = + Hash[* + (Hash.instance_methods + + %w{alias and begin break case class def defined do else elsif + end ensure false for if in module next nil not or redo + rescue retry return self super then true undef unless until + when while yield} + + %w{array element index value} + + %w{type initial_length read_until} + + %w{fields endian search_prefix hide only_if byte_align} + + %w{choices selection copy_on_change} + + %w{read_abs_offset struct_params}).collect(&:to_sym). + uniq.collect { |key| [key, true] }.flatten + ] + + def initialize_shared_instance + fields = get_parameter(:fields) + @field_names = fields.field_names.freeze + extend ByteAlignPlugin if fields.any_field_has_parameter?(:byte_align) + define_field_accessors + super + end + + def initialize_instance + @field_objs = [] + end + + def clear #:nodoc: + @field_objs.each { |f| f.clear unless f.nil? } + end + + def clear? #:nodoc: + @field_objs.all? { |f| f.nil? || f.clear? } + end + + def assign(val) + clear + assign_fields(val) + end + + def snapshot + snapshot = Snapshot.new + field_names.each do |name| + obj = find_obj_for_name(name) + snapshot[name] = obj.snapshot if include_obj?(obj) + end + snapshot + end + + # Returns a list of the names of all fields accessible through this + # object. +include_hidden+ specifies whether to include hidden names + # in the listing. + def field_names(include_hidden = false) + if include_hidden + @field_names.compact + else + hidden = get_parameter(:hide) || [] + @field_names.compact - hidden + end + end + + def debug_name_of(child) #:nodoc: + field_name = @field_names[find_index_of(child)] + "#{debug_name}.#{field_name}" + end + + def offset_of(child) #:nodoc: + instantiate_all_objs + sum = sum_num_bytes_below_index(find_index_of(child)) + child.bit_aligned? ? sum.floor : sum.ceil + end + + def do_read(io) #:nodoc: + instantiate_all_objs + @field_objs.each { |f| f.do_read(io) if include_obj?(f) } + end + + def do_write(io) #:nodoc + instantiate_all_objs + @field_objs.each { |f| f.do_write(io) if include_obj?(f) } + end + + def do_num_bytes #:nodoc: + instantiate_all_objs + sum_num_bytes_for_all_fields + end + + def [](key) + find_obj_for_name(key) + end + + def []=(key, value) + obj = find_obj_for_name(key) + if obj + obj.assign(value) + end + end + + def key?(key) + @field_names.index(base_field_name(key)) + end + + def each_pair + @field_names.compact.each do |name| + yield [name, find_obj_for_name(name)] + end + end + + #--------------- + private + + def define_field_accessors + get_parameter(:fields).each_with_index do |field, i| + name = field.name_as_sym + define_field_accessors_for(name, i) if name + end + end + + def define_field_accessors_for(name, index) + define_singleton_method(name) do + instantiate_obj_at(index) if @field_objs[index].nil? + @field_objs[index] + end + define_singleton_method("#{name}=") do |*vals| + instantiate_obj_at(index) if @field_objs[index].nil? + @field_objs[index].assign(*vals) + end + define_singleton_method("#{name}?") do + instantiate_obj_at(index) if @field_objs[index].nil? + include_obj?(@field_objs[index]) + end + end + + def find_index_of(obj) + @field_objs.index { |el| el.equal?(obj) } + end + + def find_obj_for_name(name) + index = @field_names.index(base_field_name(name)) + if index + instantiate_obj_at(index) + @field_objs[index] + else + nil + end + end + + def base_field_name(name) + name.to_s.sub(/(=|\?)\z/, "").to_sym + end + + def instantiate_all_objs + @field_names.each_index { |i| instantiate_obj_at(i) } + end + + def instantiate_obj_at(index) + if @field_objs[index].nil? + field = get_parameter(:fields)[index] + @field_objs[index] = field.instantiate(nil, self) + end + end + + def assign_fields(val) + src = as_stringified_hash(val) + + @field_names.compact.each do |name| + obj = find_obj_for_name(name) + if obj && src.key?(name) + obj.assign(src[name]) + end + end + end + + def as_stringified_hash(val) + if BinData::Struct === val + val + elsif val.nil? + {} + else + hash = Snapshot.new + val.each_pair { |k,v| hash[k] = v } + hash + end + end + + def sum_num_bytes_for_all_fields + sum_num_bytes_below_index(@field_objs.length) + end + + def sum_num_bytes_below_index(index) + (0...index).inject(0) do |sum, i| + obj = @field_objs[i] + if include_obj?(obj) + nbytes = obj.do_num_bytes + (nbytes.is_a?(Integer) ? sum.ceil : sum) + nbytes + else + sum + end + end + end + + def include_obj?(obj) + !obj.has_parameter?(:onlyif) || obj.eval_parameter(:onlyif) + end + + # A hash that can be accessed via attributes. + class Snapshot < ::Hash #:nodoc: + def []=(key, value) + super unless value.nil? + end + + def respond_to?(symbol, include_private = false) + key?(symbol) || super + end + + def method_missing(symbol, *args) + key?(symbol) ? self[symbol] : super + end + end + end + + # Align fields to a multiple of :byte_align + module ByteAlignPlugin + def do_read(io) + initial_offset = io.offset + instantiate_all_objs + @field_objs.each do |f| + if include_obj?(f) + if align_obj?(f) + io.seekbytes(bytes_to_align(f, io.offset - initial_offset)) + end + f.do_read(io) + end + end + end + + def do_write(io) + initial_offset = io.offset + instantiate_all_objs + @field_objs.each do |f| + if include_obj?(f) + if align_obj?(f) + io.writebytes("\x00" * bytes_to_align(f, io.offset - initial_offset)) + end + f.do_write(io) + end + end + end + + def sum_num_bytes_below_index(index) + sum = 0 + (0...@field_objs.length).each do |i| + obj = @field_objs[i] + if include_obj?(obj) + sum = sum.ceil + bytes_to_align(obj, sum.ceil) if align_obj?(obj) + + break if i >= index + + nbytes = obj.do_num_bytes + sum = (nbytes.is_a?(Integer) ? sum.ceil : sum) + nbytes + end + end + + sum + end + + def bytes_to_align(obj, rel_offset) + align = obj.eval_parameter(:byte_align) + (align - (rel_offset % align)) % align + end + + def align_obj?(obj) + obj.has_parameter?(:byte_align) + end + end + + class StructArgProcessor < BaseArgProcessor + def sanitize_parameters!(obj_class, params) + sanitize_endian(params) + sanitize_search_prefix(params) + sanitize_fields(obj_class, params) + sanitize_hide(params) + end + + #------------- + private + + def sanitize_endian(params) + params.sanitize_endian(:endian) + end + + def sanitize_search_prefix(params) + params.sanitize(:search_prefix) do |sprefix| + search_prefix = [] + Array(sprefix).each do |prefix| + prefix = prefix.to_s.chomp("_") + search_prefix << prefix if prefix != "" + end + + search_prefix + end + end + + def sanitize_fields(obj_class, params) + params.sanitize_fields(:fields) do |fields, sanitized_fields| + fields.each do |ftype, fname, fparams| + sanitized_fields.add_field(ftype, fname, fparams) + end + + field_names = sanitized_field_names(sanitized_fields) + ensure_field_names_are_valid(obj_class, field_names) + end + end + + def sanitize_hide(params) + params.sanitize(:hide) do |hidden| + field_names = sanitized_field_names(params[:fields]) + hfield_names = hidden_field_names(hidden) + + hfield_names & field_names + end + end + + def sanitized_field_names(sanitized_fields) + sanitized_fields.field_names.compact + end + + def hidden_field_names(hidden) + (hidden || []).collect(&:to_sym) + end + + def ensure_field_names_are_valid(obj_class, field_names) + reserved_names = BinData::Struct::RESERVED + + field_names.each do |name| + if obj_class.method_defined?(name) + raise NameError.new("Rename field '#{name}' in #{obj_class}, " \ + "as it shadows an existing method.", name) + end + if reserved_names.include?(name) + raise NameError.new("Rename field '#{name}' in #{obj_class}, " \ + "as it is a reserved name.", name) + end + if field_names.count(name) != 1 + raise NameError.new("field '#{name}' in #{obj_class}, " \ + "is defined multiple times.", name) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/trace.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/trace.rb new file mode 100644 index 0000000000000..4e4f9ba59c477 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/trace.rb @@ -0,0 +1,95 @@ +module BinData + # reference to the current tracer + @tracer ||= nil + + class Tracer #:nodoc: + def initialize(io) + @trace_io = io + end + + def trace(msg) + @trace_io.puts(msg) + end + + def trace_obj(obj_name, val) + if val.length > 30 + val = val.slice(0..30) + "..." + end + + trace "#{obj_name} => #{val}" + end + end + + # Turn on trace information when reading a BinData object. + # If +block+ is given then the tracing only occurs for that block. + # This is useful for debugging a BinData declaration. + def trace_reading(io = STDERR) + @tracer = Tracer.new(io) + [BasePrimitive, Choice].each(&:turn_on_tracing) + + if block_given? + begin + yield + ensure + [BasePrimitive, Choice].each(&:turn_off_tracing) + @tracer = nil + end + end + end + + def trace_message #:nodoc: + yield @tracer if @tracer + end + + module_function :trace_reading, :trace_message + + class BasePrimitive < BinData::Base + class << self + def turn_on_tracing + alias_method :do_read_without_hook, :do_read + alias_method :do_read, :do_read_with_hook + end + + def turn_off_tracing + alias_method :do_read, :do_read_without_hook + end + end + + def do_read_with_hook(io) + do_read_without_hook(io) + trace_value + end + + def trace_value + BinData.trace_message do |tracer| + value_string = _value.inspect + tracer.trace_obj(debug_name, value_string) + end + end + end + + class Choice < BinData::Base + class << self + def turn_on_tracing + alias_method :do_read_without_hook, :do_read + alias_method :do_read, :do_read_with_hook + end + + def turn_off_tracing + alias_method :do_read, :do_read_without_hook + end + end + + def do_read_with_hook(io) + trace_selection + do_read_without_hook(io) + end + + def trace_selection + BinData.trace_message do |tracer| + selection_string = eval_parameter(:selection).inspect + tracer.trace_obj("#{debug_name}-selection-", selection_string) + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/uint8_array.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/uint8_array.rb new file mode 100644 index 0000000000000..72816611e8eeb --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/uint8_array.rb @@ -0,0 +1,62 @@ +require "bindata/base_primitive" + +module BinData + # Uint8Array is a specialised type of array that only contains + # bytes (Uint8). It is a faster and more memory efficient version + # of `BinData::Array.new(:type => :uint8)`. + # + # require 'bindata' + # + # obj = BinData::Uint8Array.new(initial_length: 5) + # obj.read("abcdefg") #=> [97, 98, 99, 100, 101] + # obj[2] #=> 99 + # obj.collect { |x| x.chr }.join #=> "abcde" + # + # == Parameters + # + # Parameters may be provided at initialisation to control the behaviour of + # an object. These params are: + # + # :initial_length:: The initial length of the array. + # :read_until:: May only have a value of `:eof`. This parameter + # instructs the array to read as much data from + # the stream as possible. + class Uint8Array < BinData::BasePrimitive + optional_parameters :initial_length, :read_until + mutually_exclusive_parameters :initial_length, :read_until + arg_processor :uint8_array + + #--------------- + private + + def value_to_binary_string(val) + val.pack("C*") + end + + def read_and_return_value(io) + if has_parameter?(:initial_length) + data = io.readbytes(eval_parameter(:initial_length)) + else + data = io.read_all_bytes + end + + data.unpack("C*") + end + + def sensible_default + [] + end + end + + class Uint8ArrayArgProcessor < BaseArgProcessor + def sanitize_parameters!(obj_class, params) #:nodoc: + # ensure one of :initial_length and :read_until exists + unless params.has_at_least_one_of?(:initial_length, :read_until) + params[:initial_length] = 0 + end + + msg = "Parameter :read_until must have a value of :eof" + params.sanitize(:read_until) { |val| raise ArgumentError, msg unless val == :eof } + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/version.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/version.rb new file mode 100644 index 0000000000000..0a79a6ac62b29 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/version.rb @@ -0,0 +1,3 @@ +module BinData + VERSION = "2.4.4" +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/virtual.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/virtual.rb new file mode 100644 index 0000000000000..1a7205f74bf83 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/virtual.rb @@ -0,0 +1,47 @@ +require "bindata/base" + +module BinData + # A virtual field is one that is neither read, written nor occupies space in + # the data stream. It is used to make assertions or as a convenient label + # for determining offsets or storing values. + # + # require 'bindata' + # + # class A < BinData::Record + # string :a, read_length: 5 + # string :b, read_length: 5 + # virtual :c, assert: -> { a == b } + # end + # + # obj = A.read("abcdeabcde") + # obj.a #=> "abcde" + # obj.c.offset #=> 10 + # + # obj = A.read("abcdeABCDE") #=> BinData::ValidityError: assertion failed for obj.c + # + # == Parameters + # + # Parameters may be provided at initialisation to control the behaviour of + # an object. These params include those for BinData::Base as well as: + # + # [:assert] Raise an error when reading or assigning if the value + # of this evaluated parameter is false. + # [:value] The virtual object will always have this value. + # + class Virtual < BinData::BasePrimitive + + def do_read(io) + end + + def do_write(io) + end + + def do_num_bytes + 0.0 + end + + def sensible_default + nil + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/warnings.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/warnings.rb new file mode 100644 index 0000000000000..3d1cfe728be72 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/bindata-2.4.4/lib/bindata/warnings.rb @@ -0,0 +1,36 @@ +module BinData + class Base + # Don't override initialize. If you are defining a new kind of datatype + # (list, array, choice etc) then put your initialization code in + # #initialize_instance. BinData objects might be initialized as prototypes + # and your initialization code may not be called. + # + # If you're subclassing BinData::Record, you are definitely doing the wrong + # thing. Read the documentation on how to use BinData. + # http://github.com/dmendel/bindata/wiki/Records + alias_method :initialize_without_warning, :initialize + def initialize_with_warning(*args) + owner = method(:initialize).owner + if owner != BinData::Base + msg = "Don't override #initialize on #{owner}." + if %w(BinData::Base BinData::BasePrimitive).include? self.class.superclass.name + msg += "\nrename #initialize to #initialize_instance." + end + fail msg + end + initialize_without_warning(*args) + end + alias initialize initialize_with_warning + + def initialize_instance(*args) + unless args.empty? + fail "#{caller[0]} remove the call to super in #initialize_instance" + end + end + end + + class Struct + # has_key? is deprecated + alias has_key? key? + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools.rb new file mode 100644 index 0000000000000..2b16c7ef8cbcc --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require 'elftools/constants' +require 'elftools/elf_file' +require 'elftools/version' + +# The ELF parsing tools! +# Main entry point is {ELFTools::ELFFile}, see it +# for more information. +module ELFTools +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/constants.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/constants.rb new file mode 100644 index 0000000000000..197ec969d0137 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/constants.rb @@ -0,0 +1,303 @@ +# frozen_string_literal: true + +module ELFTools + # Define constants from elf.h. + # Mostly refer from https://github.com/torvalds/linux/blob/master/include/uapi/linux/elf.h + # and binutils/elfcpp/elfcpp.h. + module Constants + # ELF magic header + ELFMAG = "\x7FELF" + + # Values of `d_un.d_val' in the DT_FLAGS and DT_FLAGS_1 entry. + module DF + DF_ORIGIN = 0x00000001 # Object may use DF_ORIGIN + DF_SYMBOLIC = 0x00000002 # Symbol resolutions starts here + DF_TEXTREL = 0x00000004 # Object contains text relocations + DF_BIND_NOW = 0x00000008 # No lazy binding for this object + DF_STATIC_TLS = 0x00000010 # Module uses the static TLS model + + DF_1_NOW = 0x00000001 # Set RTLD_NOW for this object. + DF_1_GLOBAL = 0x00000002 # Set RTLD_GLOBAL for this object. + DF_1_GROUP = 0x00000004 # Set RTLD_GROUP for this object. + DF_1_NODELETE = 0x00000008 # Set RTLD_NODELETE for this object. + DF_1_LOADFLTR = 0x00000010 # Trigger filtee loading at runtime. + DF_1_INITFIRST = 0x00000020 # Set RTLD_INITFIRST for this object + DF_1_NOOPEN = 0x00000040 # Set RTLD_NOOPEN for this object. + DF_1_ORIGIN = 0x00000080 # $ORIGIN must be handled. + DF_1_DIRECT = 0x00000100 # Direct binding enabled. + DF_1_TRANS = 0x00000200 # :nodoc: + DF_1_INTERPOSE = 0x00000400 # Object is used to interpose. + DF_1_NODEFLIB = 0x00000800 # Ignore default lib search path. + DF_1_NODUMP = 0x00001000 # Object can't be dldump'ed. + DF_1_CONFALT = 0x00002000 # Configuration alternative created. + DF_1_ENDFILTEE = 0x00004000 # Filtee terminates filters search. + DF_1_DISPRELDNE = 0x00008000 # Disp reloc applied at build time. + DF_1_DISPRELPND = 0x00010000 # Disp reloc applied at run-time. + DF_1_NODIRECT = 0x00020000 # Object has no-direct binding. + DF_1_IGNMULDEF = 0x00040000 # :nodoc: + DF_1_NOKSYMS = 0x00080000 # :nodoc: + DF_1_NOHDR = 0x00100000 # :nodoc: + DF_1_EDITED = 0x00200000 # Object is modified after built. + DF_1_NORELOC = 0x00400000 # :nodoc: + DF_1_SYMINTPOSE = 0x00800000 # Object has individual interposers. + DF_1_GLOBAUDIT = 0x01000000 # Global auditing required. + DF_1_SINGLETON = 0x02000000 # Singleton symbols are used. + end + include DF + + # Dynamic table types, records in +d_tag+. + module DT + DT_NULL = 0 # marks the end of the _DYNAMIC array + DT_NEEDED = 1 # libraries need to be linked by loader + DT_PLTRELSZ = 2 # total size of relocation entries + DT_PLTGOT = 3 # address of procedure linkage table or global offset table + DT_HASH = 4 # address of symbol hash table + DT_STRTAB = 5 # address of string table + DT_SYMTAB = 6 # address of symbol table + DT_RELA = 7 # address of a relocation table + DT_RELASZ = 8 # total size of the {DT_RELA} table + DT_RELAENT = 9 # size of each entry in the {DT_RELA} table + DT_STRSZ = 10 # total size of {DT_STRTAB} + DT_SYMENT = 11 # size of each entry in {DT_SYMTAB} + DT_INIT = 12 # where the initialization function is + DT_FINI = 13 # where the termination function is + DT_SONAME = 14 # the shared object name + DT_RPATH = 15 # has been superseded by {DT_RUNPATH} + DT_SYMBOLIC = 16 # has been superseded by the DF_SYMBOLIC flag + DT_REL = 17 # similar to {DT_RELA} + DT_RELSZ = 18 # total size of the {DT_REL} table + DT_RELENT = 19 # size of each entry in the {DT_REL} table + DT_PLTREL = 20 # type of relocation entry, either {DT_REL} or {DT_RELA} + DT_DEBUG = 21 # for debugging + DT_TEXTREL = 22 # has been superseded by the DF_TEXTREL flag + DT_JMPREL = 23 # address of relocation entries that are associated solely with the procedure linkage table + DT_BIND_NOW = 24 # if the loader needs to do relocate now, superseded by the DF_BIND_NOW flag + DT_INIT_ARRAY = 25 # address init array + DT_FINI_ARRAY = 26 # address of fini array + DT_INIT_ARRAYSZ = 27 # total size of init array + DT_FINI_ARRAYSZ = 28 # total size of fini array + DT_RUNPATH = 29 # path of libraries for searching + DT_FLAGS = 30 # flags + DT_ENCODING = 32 # just a lower bound + # Values between {DT_LOOS} and {DT_HIOS} are reserved for operating system-specific semantics. + DT_LOOS = 0x6000000d + DT_HIOS = 0x6ffff000 # see {DT_LOOS} + # Values between {DT_VALRNGLO} and {DT_VALRNGHI} use the +d_un.d_val+ field of the dynamic structure. + DT_VALRNGLO = 0x6ffffd00 + DT_VALRNGHI = 0x6ffffdff # see {DT_VALRNGLO} + # Values between {DT_ADDRRNGLO} and {DT_ADDRRNGHI} use the +d_un.d_ptr+ field of the dynamic structure. + DT_ADDRRNGLO = 0x6ffffe00 + DT_GNU_HASH = 0x6ffffef5 # the gnu hash + DT_ADDRRNGHI = 0x6ffffeff # see {DT_ADDRRNGLO} + DT_RELACOUNT = 0x6ffffff9 # relative relocation count + DT_RELCOUNT = 0x6ffffffa # relative relocation count + DT_FLAGS_1 = 0x6ffffffb # flags + DT_VERDEF = 0x6ffffffc # address of version definition table + DT_VERDEFNUM = 0x6ffffffd # number of entries in {DT_VERDEF} + DT_VERNEED = 0x6ffffffe # address of version dependency table + DT_VERNEEDNUM = 0x6fffffff # number of entries in {DT_VERNEED} + # Values between {DT_LOPROC} and {DT_HIPROC} are reserved for processor-specific semantics. + DT_LOPROC = 0x70000000 + DT_HIPROC = 0x7fffffff # see {DT_LOPROC} + end + include DT + + # These constants define the various ELF target machines. + module EM + EM_NONE = 0 # none + EM_M32 = 1 # AT&T WE 32100 + EM_SPARC = 2 # SPARC + EM_386 = 3 # Intel 80386 + EM_68K = 4 # Motorola 68000 + EM_88K = 5 # Motorola 88000 + EM_486 = 6 # Intel 80486 + EM_860 = 7 # Intel 80860 + EM_MIPS = 8 # MIPS R3000 (officially, big-endian only) + + # Next two are historical and binaries and + # modules of these types will be rejected by Linux. + EM_MIPS_RS3_LE = 10 # MIPS R3000 little-endian + EM_MIPS_RS4_BE = 10 # MIPS R4000 big-endian + + EM_PARISC = 15 # HPPA + EM_SPARC32PLUS = 18 # Sun's "v8plus" + EM_PPC = 20 # PowerPC + EM_PPC64 = 21 # PowerPC64 + EM_SPU = 23 # Cell BE SPU + EM_ARM = 40 # ARM 32 bit + EM_SH = 42 # SuperH + EM_SPARCV9 = 43 # SPARC v9 64-bit + EM_H8_300 = 46 # Renesas H8/300 + EM_IA_64 = 50 # HP/Intel IA-64 + EM_X86_64 = 62 # AMD x86-64 + EM_S390 = 22 # IBM S/390 + EM_CRIS = 76 # Axis Communications 32-bit embedded processor + EM_M32R = 88 # Renesas M32R + EM_MN10300 = 89 # Panasonic/MEI MN10300, AM33 + EM_OPENRISC = 92 # OpenRISC 32-bit embedded processor + EM_BLACKFIN = 106 # ADI Blackfin Processor + EM_ALTERA_NIOS2 = 113 # Altera Nios II soft-core processor + EM_TI_C6000 = 140 # TI C6X DSPs + EM_AARCH64 = 183 # ARM 64 bit + EM_TILEPRO = 188 # Tilera TILEPro + EM_MICROBLAZE = 189 # Xilinx MicroBlaze + EM_TILEGX = 191 # Tilera TILE-Gx + EM_BPF = 247 # Linux BPF - in-kernel virtual machine + EM_FRV = 0x5441 # Fujitsu FR-V + EM_AVR32 = 0x18ad # Atmel AVR32 + + # This is an interim value that we will use until the committee comes up with a final number. + EM_ALPHA = 0x9026 + + # Bogus old m32r magic number, used by old tools. + EM_CYGNUS_M32R = 0x9041 + # This is the old interim value for S/390 architecture + EM_S390_OLD = 0xA390 + # Also Panasonic/MEI MN10300, AM33 + EM_CYGNUS_MN10300 = 0xbeef + + # Return the architecture name according to +val+. + # Used by {ELFTools::ELFFile#machine}. + # + # Only supports famous archs. + # @param [Integer] val Value of +e_machine+. + # @return [String] + # Name of architecture. + # @example + # mapping(3) + # #=> 'Intel 80386' + # mapping(6) + # #=> 'Intel 80386' + # mapping(62) + # #=> 'Advanced Micro Devices X86-64' + # mapping(1337) + # #=> ': 0x539' + def self.mapping(val) + case val + when EM_NONE then 'None' + when EM_386, EM_486 then 'Intel 80386' + when EM_860 then 'Intel 80860' + when EM_MIPS then 'MIPS R3000' + when EM_PPC then 'PowerPC' + when EM_PPC64 then 'PowerPC64' + when EM_ARM then 'ARM' + when EM_IA_64 then 'Intel IA-64' + when EM_AARCH64 then 'AArch64' + when EM_X86_64 then 'Advanced Micro Devices X86-64' + else format(': 0x%x', val) + end + end + end + include EM + + # This module defines elf file types. + module ET + ET_NONE = 0 # no file type + ET_REL = 1 # relocatable file + ET_EXEC = 2 # executable file + ET_DYN = 3 # shared object + ET_CORE = 4 # core file + # Return the type name according to +e_type+ in ELF file header. + # @return [String] Type in string format. + def self.mapping(type) + case type + when Constants::ET_NONE then 'NONE' + when Constants::ET_REL then 'REL' + when Constants::ET_EXEC then 'EXEC' + when Constants::ET_DYN then 'DYN' + when Constants::ET_CORE then 'CORE' + else '' + end + end + end + include ET + + # Program header types, records in +p_type+. + module PT + PT_NULL = 0 # null segment + PT_LOAD = 1 # segment to be load + PT_DYNAMIC = 2 # dynamic tags + PT_INTERP = 3 # interpreter, same as .interp section + PT_NOTE = 4 # same as .note* section + PT_SHLIB = 5 # reserved + PT_PHDR = 6 # where program header starts + PT_TLS = 7 # thread local storage segment + PT_LOOS = 0x60000000 # OS-specific + PT_HIOS = 0x6fffffff # OS-specific + # Values between {PT_LOPROC} and {PT_HIPROC} are reserved for processor-specific semantics. + PT_LOPROC = 0x70000000 + PT_HIPROC = 0x7fffffff # see {PT_LOPROC} + PT_GNU_EH_FRAME = 0x6474e550 # for exception handler + PT_GNU_STACK = 0x6474e551 # permission of stack + PT_GNU_RELRO = 0x6474e552 # read only after relocation + end + include PT + + # Section header types, records in +sh_type+. + module SHT + SHT_NULL = 0 # null section + SHT_PROGBITS = 1 # information defined by program itself + SHT_SYMTAB = 2 # symbol table section + SHT_STRTAB = 3 # string table section + SHT_RELA = 4 # relocation with addends + SHT_HASH = 5 # symbol hash table + SHT_DYNAMIC = 6 # information of dynamic linking + SHT_NOTE = 7 # note section + SHT_NOBITS = 8 # section occupies no space + SHT_REL = 9 # relocation + SHT_SHLIB = 10 # reserved + SHT_DYNSYM = 11 # symbols for dynamic + # Values between {SHT_LOPROC} and {SHT_HIPROC} are reserved for processor-specific semantics. + SHT_LOPROC = 0x70000000 + SHT_HIPROC = 0x7fffffff # see {SHT_LOPROC} + # Values between {SHT_LOUSER} and {SHT_HIUSER} are reserved for application programs. + SHT_LOUSER = 0x80000000 + SHT_HIUSER = 0xffffffff # see {SHT_LOUSER} + end + include SHT + + # Symbol binding from Sym st_info field. + module STB + STB_LOCAL = 0 # Local symbol + STB_GLOBAL = 1 # Global symbol + STB_WEAK = 2 # Weak symbol + STB_NUM = 3 # Number of defined types. + STB_LOOS = 10 # Start of OS-specific + STB_GNU_UNIQUE = 10 # Unique symbol. + STB_HIOS = 12 # End of OS-specific + STB_LOPROC = 13 # Start of processor-specific + STB_HIPROC = 15 # End of processor-specific + end + include STB + + # Symbol types from Sym st_info field. + module STT + STT_NOTYPE = 0 # Symbol type is unspecified + STT_OBJECT = 1 # Symbol is a data object + STT_FUNC = 2 # Symbol is a code object + STT_SECTION = 3 # Symbol associated with a section + STT_FILE = 4 # Symbol's name is file name + STT_COMMON = 5 # Symbol is a common data object + STT_TLS = 6 # Symbol is thread-local data object + STT_NUM = 7 # Number of defined types. + + # GNU extension: symbol value points to a function which is called + # at runtime to determine the final value of the symbol. + STT_GNU_IFUNC = 10 + + STT_LOOS = 10 # Start of OS-specific + STT_HIOS = 12 # End of OS-specific + STT_LOPROC = 13 # Start of processor-specific + STT_HIPROC = 15 # End of processor-specific + + # The section type that must be used for register symbols on + # Sparc. These symbols initialize a global register. + STT_SPARC_REGISTER = 13 + + # ARM: a THUMB function. This is not defined in ARM ELF Specification but + # used by the GNU tool-chain. + STT_ARM_TFUNC = 13 + end + include STT + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/dynamic.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/dynamic.rb new file mode 100644 index 0000000000000..3295504cb5d96 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/dynamic.rb @@ -0,0 +1,178 @@ +# frozen_string_literal: true + +module ELFTools + # Define common methods for dynamic sections and dynamic segments. + # + # @note + # This module can only be included by {ELFTools::Sections::DynamicSection} + # and {ELFTools::Segments::DynamicSegment} because methods here assume some + # attributes exist. + module Dynamic + # Iterate all tags. + # + # @note + # This method assume the following methods already exist: + # header + # tag_start + # @yieldparam [ELFTools::Dynamic::Tag] tag + # @return [Enumerator, Array] + # If block is not given, an enumerator will be returned. + # Otherwise, return array of tags. + def each_tags(&block) + return enum_for(:each_tags) unless block_given? + + arr = [] + 0.step do |i| + tag = tag_at(i).tap(&block) + arr << tag + break if tag.header.d_tag == ELFTools::Constants::DT_NULL + end + arr + end + + # Use {#tags} to get all tags. + # @return [Array] + # Array of tags. + def tags + @tags ||= each_tags.to_a + end + + # Get a tag of specific type. + # @param [Integer, Symbol, String] type + # Constant value, symbol, or string of type + # is acceptable. See examples for more information. + # @return [ELFTools::Dynamic::Tag] The desired tag. + # @example + # dynamic = elf.segment_by_type(:dynamic) + # # type as integer + # dynamic.tag_by_type(0) # the null tag + # #=> #0, :d_val=>0}> + # dynamic.tag_by_type(ELFTools::Constants::DT_NULL) + # #=> #0, :d_val=>0}> + # + # # symbol + # dynamic.tag_by_type(:null) + # #=> #0, :d_val=>0}> + # dynamic.tag_by_type(:pltgot) + # #=> #3, :d_val=>6295552}> + # + # # string + # dynamic.tag_by_type('null') + # #=> #0, :d_val=>0}> + # dynamic.tag_by_type('DT_PLTGOT') + # #=> #3, :d_val=>6295552}> + def tag_by_type(type) + type = Util.to_constant(Constants::DT, type) + each_tags.find { |tag| tag.header.d_tag == type } + end + + # Get tags of specific type. + # @param [Integer, Symbol, String] type + # Constant value, symbol, or string of type + # is acceptable. See examples for more information. + # @return [Array] The desired tags. + # + # @see #tag_by_type + def tags_by_type(type) + type = Util.to_constant(Constants::DT, type) + each_tags.select { |tag| tag.header.d_tag == type } + end + + # Get the +n+-th tag. + # + # Tags are lazy loaded. + # @note + # This method assume the following methods already exist: + # header + # tag_start + # @note + # We cannot do bound checking of +n+ here since the only way to get size + # of tags is calling +tags.size+. + # @param [Integer] n The index. + # @return [ELFTools::Dynamic::Tag] The desired tag. + def tag_at(n) + return if n.negative? + + @tag_at_map ||= {} + return @tag_at_map[n] if @tag_at_map[n] + + dyn = Structs::ELF_Dyn.new(endian: endian) + dyn.elf_class = header.elf_class + stream.pos = tag_start + n * dyn.num_bytes + dyn.offset = stream.pos + @tag_at_map[n] = Tag.new(dyn.read(stream), stream, method(:str_offset)) + end + + private + + def endian + header.class.self_endian + end + + # Get the DT_STRTAB's +d_val+ offset related to file. + def str_offset + # TODO: handle DT_STRTAB not exitsts. + @str_offset ||= @offset_from_vma.call(tag_by_type(:strtab).header.d_val.to_i) + end + + # A tag class. + class Tag + attr_reader :header # @return [ELFTools::Structs::ELF_Dyn] The dynamic tag header. + attr_reader :stream # @return [#pos=, #read] Streaming object. + + # Instantiate a {ELFTools::Dynamic::Tag} object. + # @param [ELF_Dyn] header The dynamic tag header. + # @param [#pos=, #read] stream Streaming object. + # @param [Method] str_offset + # Call this method to get the string offset related + # to file. + def initialize(header, stream, str_offset) + @header = header + @stream = stream + @str_offset = str_offset + end + + # Some dynamic have name. + TYPE_WITH_NAME = [Constants::DT_NEEDED, + Constants::DT_SONAME, + Constants::DT_RPATH, + Constants::DT_RUNPATH].freeze + # Return the content of this tag records. + # + # For normal tags, this method just return + # +header.d_val+. For tags with +header.d_val+ + # in meaning of string offset (e.g. DT_NEEDED), this method would + # return the string it specified. + # Tags with type in {TYPE_WITH_NAME} are those tags with name. + # @return [Integer, String] The content this tag records. + # @example + # dynamic = elf.segment_by_type(:dynamic) + # dynamic.tag_by_type(:init).value + # #=> 4195600 # 0x400510 + # dynamic.tag_by_type(:needed).value + # #=> 'libc.so.6' + def value + name || header.d_val.to_i + end + + # Is this tag has a name? + # + # The criteria here is if this tag's type is in {TYPE_WITH_NAME}. + # @return [Boolean] Is this tag has a name. + def name? + TYPE_WITH_NAME.include?(header.d_tag) + end + + # Return the name of this tag. + # + # Only tags with name would return a name. + # Others would return +nil+. + # @return [String, nil] The name. + def name + return nil unless name? + + Util.cstring(stream, @str_offset.call + header.d_val.to_i) + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/elf_file.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/elf_file.rb new file mode 100644 index 0000000000000..3b58d27330ab8 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/elf_file.rb @@ -0,0 +1,377 @@ +# frozen_string_literal: true + +require 'elftools/constants' +require 'elftools/exceptions' +require 'elftools/lazy_array' +require 'elftools/sections/sections' +require 'elftools/segments/segments' +require 'elftools/structs' + +module ELFTools + # The main class for using elftools. + class ELFFile + attr_reader :stream # @return [#pos=, #read] The +File+ object. + attr_reader :elf_class # @return [Integer] 32 or 64. + attr_reader :endian # @return [Symbol] +:little+ or +:big+. + + # Instantiate an {ELFFile} object. + # + # @param [#pos=, #read] stream + # The +File+ object to be fetch information from. + # @example + # ELFFile.new(File.open('/bin/cat')) + # #=> #> + def initialize(stream) + @stream = stream + # always set binmode if stream is an IO object. + @stream.binmode if @stream.respond_to?(:binmode) + identify # fetch the most basic information + end + + # Return the file header. + # + # Lazy loading. + # @return [ELFTools::Structs::ELF_Ehdr] The header. + def header + return @header if defined?(@header) + + stream.pos = 0 + @header = Structs::ELF_Ehdr.new(endian: endian, offset: stream.pos) + @header.elf_class = elf_class + @header.read(stream) + end + + # Return the BuildID of ELF. + # @return [String, nil] + # BuildID in hex form will be returned. + # +nil+ is returned if the .note.gnu.build-id section + # is not found. + # @example + # elf.build_id + # #=> '73ab62cb7bc9959ce053c2b711322158708cdc07' + def build_id + section = section_by_name('.note.gnu.build-id') + return nil if section.nil? + + note = section.notes.first + return nil if note.nil? + + note.desc.unpack('H*').first + end + + # Get machine architecture. + # + # Mappings of architecture can be found + # in {ELFTools::Constants::EM.mapping}. + # @return [String] + # Name of architecture. + # @example + # elf.machine + # #=> 'Advanced Micro Devices X86-64' + def machine + ELFTools::Constants::EM.mapping(header.e_machine) + end + + # Return the ELF type according to +e_type+. + # @return [String] Type in string format. + # @example + # ELFFile.new(File.open('spec/files/libc.so.6')).elf_type + # #=> 'DYN' + # ELFFile.new(File.open('spec/files/amd64.elf')).elf_type + # #=> 'EXEC' + def elf_type + ELFTools::Constants::ET.mapping(header.e_type) + end + + #========= method about sections + + # Number of sections in this file. + # @return [Integer] The desired number. + # @example + # elf.num_sections + # #=> 29 + def num_sections + header.e_shnum + end + + # Acquire the section named as +name+. + # @param [String] name The desired section name. + # @return [ELFTools::Sections::Section, nil] The target section. + # @example + # elf.section_by_name('.note.gnu.build-id') + # #=> # + # elf.section_by_name('') + # #=> # + # elf.section_by_name('no such section') + # #=> nil + def section_by_name(name) + each_sections.find { |sec| sec.name == name } + end + + # Iterate all sections. + # + # All sections are lazy loading, the section + # only be created whenever accessing it. + # This method is useful for {#section_by_name} + # since not all sections need to be created. + # @yieldparam [ELFTools::Sections::Section] section A section. + # @yieldreturn [void] + # @return [Enumerator, Array] + # As +Array#each+, if block is not given, a enumerator will be returned, + # otherwise, the whole sections will be returned. + def each_sections(&block) + return enum_for(:each_sections) unless block_given? + + Array.new(num_sections) do |i| + section_at(i).tap(&block) + end + end + + # Simply use {#sections} to get all sections. + # @return [Array] + # Whole sections. + def sections + each_sections.to_a + end + + # Acquire the +n+-th section, 0-based. + # + # Sections are lazy loaded. + # @param [Integer] n The index. + # @return [ELFTools::Sections::Section, nil] + # The target section. + # If +n+ is out of bound, +nil+ is returned. + def section_at(n) + @sections ||= LazyArray.new(num_sections, &method(:create_section)) + @sections[n] + end + + # Fetch all sections with specific type. + # + # The available types are listed in {ELFTools::Constants::PT}. + # This method accept giving block. + # @param [Integer, Symbol, String] type + # The type needed, similar format as {#segment_by_type}. + # @yieldparam [ELFTools::Sections::Section] section A section in specific type. + # @yieldreturn [void] + # @return [Array] The target sections. + # @example + # elf = ELFTools::ELFFile.new(File.open('spec/files/amd64.elf')) + # elf.sections_by_type(:rela) + # #=> [#, + # # #] + def sections_by_type(type, &block) + type = Util.to_constant(Constants::SHT, type) + Util.select_by_type(each_sections, type, &block) + end + + # Get the string table section. + # + # This section is acquired by using the +e_shstrndx+ + # in ELF header. + # @return [ELFTools::Sections::StrTabSection] The desired section. + def strtab_section + section_at(header.e_shstrndx) + end + + #========= method about segments + + # Number of segments in this file. + # @return [Integer] The desited number. + def num_segments + header.e_phnum + end + + # Iterate all segments. + # + # All segments are lazy loading, the segment + # only be created whenever accessing it. + # This method is useful for {#segment_by_type} + # since not all segments need to be created. + # @yieldparam [ELFTools::Segments::Segment] segment A segment. + # @yieldreturn [void] + # @return [Array] + # Whole segments will be returned. + def each_segments(&block) + return enum_for(:each_segments) unless block_given? + + Array.new(num_segments) do |i| + segment_at(i).tap(&block) + end + end + + # Simply use {#segments} to get all segments. + # @return [Array] + # Whole segments. + def segments + each_segments.to_a + end + + # Get the first segment with +p_type=type+. + # The available types are listed in {ELFTools::Constants::PT}. + # + # @note + # This method will return the first segment found, + # to found all segments with specific type you can use {#segments_by_type}. + # @param [Integer, Symbol, String] type + # See examples for clear usage. + # @return [ELFTools::Segments::Segment] The target segment. + # @example + # # type as an integer + # elf.segment_by_type(ELFTools::Constants::PT_NOTE) + # #=> # + # + # elf.segment_by_type(4) # PT_NOTE + # #=> # + # + # # type as a symbol + # elf.segment_by_type(:PT_NOTE) + # #=> # + # + # # you can do this + # elf.segment_by_type(:note) # will be transformed into `PT_NOTE` + # #=> # + # + # # type as a string + # elf.segment_by_type('PT_NOTE') + # #=> # + # + # # this is ok + # elf.segment_by_type('note') # will be tranformed into `PT_NOTE` + # #=> # + # @example + # elf.segment_by_type(1337) + # # ArgumentError: No constants in Constants::PT is 1337 + # + # elf.segment_by_type('oao') + # # ArgumentError: No constants in Constants::PT named "PT_OAO" + # @example + # elf.segment_by_type(0) + # #=> nil # no such segment exists + def segment_by_type(type) + type = Util.to_constant(Constants::PT, type) + each_segments.find { |seg| seg.header.p_type == type } + end + + # Fetch all segments with specific type. + # + # If you want to find only one segment, + # use {#segment_by_type} instead. + # This method accept giving block. + # @param [Integer, Symbol, String] type + # The type needed, same format as {#segment_by_type}. + # @yieldparam [ELFTools::Segments::Segment] segment A segment in specific type. + # @yieldreturn [void] + # @return [Array] The target segments. + def segments_by_type(type, &block) + type = Util.to_constant(Constants::PT, type) + Util.select_by_type(each_segments, type, &block) + end + + # Acquire the +n+-th segment, 0-based. + # + # Segments are lazy loaded. + # @param [Integer] n The index. + # @return [ELFTools::Segments::Segment, nil] + # The target segment. + # If +n+ is out of bound, +nil+ is returned. + def segment_at(n) + @segments ||= LazyArray.new(num_segments, &method(:create_segment)) + @segments[n] + end + + # Get the offset related to file, given virtual memory address. + # + # This method should work no matter ELF is a PIE or not. + # This method refers from (actually equals to) binutils/readelf.c#offset_from_vma. + # @param [Integer] vma The virtual address to be queried. + # @return [Integer] Related file offset. + # @example + # elf = ELFTools::ELFFile.new(File.open('/bin/cat')) + # elf.offset_from_vma(0x401337) + # #=> 4919 # 0x1337 + def offset_from_vma(vma, size = 0) + segments_by_type(:load) do |seg| + return seg.vma_to_offset(vma) if seg.vma_in?(vma, size) + end + end + + # The patch status. + # @return [Hash{Integer => String}] + def patches + patch = {} + loaded_headers.each do |header| + header.patches.each do |key, val| + patch[key + header.offset] = val + end + end + patch + end + + # Apply patches and save as +filename+. + # + # @param [String] filename + # @return [void] + def save(filename) + stream.pos = 0 + all = stream.read.force_encoding('ascii-8bit') + patches.each do |pos, val| + all[pos, val.size] = val + end + IO.binwrite(filename, all) + end + + private + + # bad idea.. + def loaded_headers + explore = lambda do |obj| + return obj if obj.is_a?(::ELFTools::Structs::ELFStruct) + return obj.map(&explore) if obj.is_a?(Array) + + obj.instance_variables.map do |s| + explore.call(obj.instance_variable_get(s)) + end + end + explore.call(self).flatten + end + + def identify + stream.pos = 0 + magic = stream.read(4) + raise ELFMagicError, "Invalid magic number #{magic.inspect}" unless magic == Constants::ELFMAG + + ei_class = stream.read(1).ord + @elf_class = { + 1 => 32, + 2 => 64 + }[ei_class] + raise ELFClassError, format('Invalid EI_CLASS "\x%02x"', ei_class) if elf_class.nil? + + ei_data = stream.read(1).ord + @endian = { + 1 => :little, + 2 => :big + }[ei_data] + raise ELFDataError, format('Invalid EI_DATA "\x%02x"', ei_data) if endian.nil? + end + + def create_section(n) + stream.pos = header.e_shoff + n * header.e_shentsize + shdr = Structs::ELF_Shdr.new(endian: endian, offset: stream.pos) + shdr.elf_class = elf_class + shdr.read(stream) + Sections::Section.create(shdr, stream, + offset_from_vma: method(:offset_from_vma), + strtab: method(:strtab_section), + section_at: method(:section_at)) + end + + def create_segment(n) + stream.pos = header.e_phoff + n * header.e_phentsize + phdr = Structs::ELF_Phdr[elf_class].new(endian: endian, offset: stream.pos) + phdr.elf_class = elf_class + Segments::Segment.create(phdr.read(stream), stream, offset_from_vma: method(:offset_from_vma)) + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/exceptions.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/exceptions.rb new file mode 100644 index 0000000000000..1d516ff22b3c4 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/exceptions.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module ELFTools + # Being raised when parsing error. + class ELFError < StandardError; end + + # Raised on invalid ELF magic. + class ELFMagicError < ELFError; end + + # Raised on invalid ELF class (EI_CLASS). + class ELFClassError < ELFError; end + + # Raised on invalid ELF data encoding (EI_DATA). + class ELFDataError < ELFError; end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/lazy_array.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/lazy_array.rb new file mode 100644 index 0000000000000..f272e0a9335a2 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/lazy_array.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +module ELFTools + # A helper class for {ELFTools} easy to implement + # 'lazy loading' objects. + # Mainly used when loading sections, segments, and + # symbols. + class LazyArray + # Instantiate a {LazyArray} object. + # @param [Integer] size + # The size of array. + # @yieldparam [Integer] i + # Needs the +i+-th element. + # @yieldreturn [Object] + # Value of the +i+-th element. + # @example + # arr = LazyArray.new(10) { |i| p "calc #{i}"; i * i } + # p arr[2] + # # "calc 2" + # # 4 + # + # p arr[3] + # # "calc 3" + # # 9 + # + # p arr[3] + # # 9 + def initialize(size, &block) + @internal = Array.new(size) + @block = block + end + + # To access elements like a normal array. + # + # Elements are lazy loaded at the first time + # access it. + # @return [Object] + # The element, returned type is the + # return type of block given in {#initialize}. + def [](i) + # XXX: support negative index? + return nil unless i.between?(0, @internal.size - 1) + + @internal[i] ||= @block.call(i) + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/note.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/note.rb new file mode 100644 index 0000000000000..5eae0338f75da --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/note.rb @@ -0,0 +1,125 @@ +# frozen_string_literal: true + +require 'elftools/structs' +require 'elftools/util' + +module ELFTools + # Since both note sections and note segments refer to notes, this module + # defines common methods for {ELFTools::Sections::NoteSection} and + # {ELFTools::Segments::NoteSegment}. + # + # @note + # This module can only be included in {ELFTools::Sections::NoteSection} and + # {ELFTools::Segments::NoteSegment} since some methods here assume some + # attributes already exist. + module Note + # Since size of {ELFTools::Structs::ELF_Nhdr} will not change no matter in + # what endian and what arch, we can do this here. This value should equal + # to 12. + SIZE_OF_NHDR = Structs::ELF_Nhdr.new(endian: :little).num_bytes + + # Iterate all notes in a note section or segment. + # + # Structure of notes are: + # +---------------+ + # | Note 1 header | + # +---------------+ + # | Note 1 name | + # +---------------+ + # | Note 1 desc | + # +---------------+ + # | Note 2 header | + # +---------------+ + # | ... | + # +---------------+ + # + # @note + # This method assume following methods exist: + # stream + # note_start + # note_total_size + # @return [Enumerator, Array] + # If block is not given, an enumerator will be returned. + # Otherwise, return the array of notes. + def each_notes + return enum_for(:each_notes) unless block_given? + + @notes_offset_map ||= {} + cur = note_start + notes = [] + while cur < note_start + note_total_size + stream.pos = cur + @notes_offset_map[cur] ||= create_note(cur) + note = @notes_offset_map[cur] + # name and desc size needs to be 4-bytes align + name_size = Util.align(note.header.n_namesz, 2) + desc_size = Util.align(note.header.n_descsz, 2) + cur += SIZE_OF_NHDR + name_size + desc_size + notes << note + yield note + end + notes + end + + # Simply +#notes+ to get all notes. + # @return [Array] + # Whole notes. + def notes + each_notes.to_a + end + + private + + # Get the endian. + # + # @note This method assume method +header+ exists. + # @return [Symbol] +:little+ or +:big+. + def endian + header.class.self_endian + end + + def create_note(cur) + nhdr = Structs::ELF_Nhdr.new(endian: endian, offset: stream.pos).read(stream) + ELFTools::Note::Note.new(nhdr, stream, cur) + end + + # Class of a note. + class Note + attr_reader :header # @return [ELFTools::Structs::ELF_Nhdr] Note header. + attr_reader :stream # @return [#pos=, #read] Streaming object. + attr_reader :offset # @return [Integer] Address of this note start, includes note header. + + # Instantiate a {ELFTools::Note::Note} object. + # @param [ELF_Nhdr] header The note header. + # @param [#pos=, #read] stream Streaming object. + # @param [Integer] offset + # Start address of this note, includes the header. + def initialize(header, stream, offset) + @header = header + @stream = stream + @offset = offset + end + + # Name of this note. + # @return [String] The name. + def name + return @name if defined?(@name) + + stream.pos = @offset + SIZE_OF_NHDR + @name = stream.read(header.n_namesz)[0..-2] + end + + # Description of this note. + # @return [String] The description. + def desc + return @desc if instance_variable_defined?(:@desc) + + stream.pos = @offset + SIZE_OF_NHDR + Util.align(header.n_namesz, 2) + @desc = stream.read(header.n_descsz) + end + + # If someone likes to use full name. + alias description desc + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/sections/dynamic_section.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/sections/dynamic_section.rb new file mode 100644 index 0000000000000..d38b04b353eaf --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/sections/dynamic_section.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require 'elftools/dynamic' +require 'elftools/sections/section' + +module ELFTools + module Sections + # Class for dynamic table section. + # + # This section should always be named .dynamic. + # This class knows how to get the list of dynamic tags. + class DynamicSection < Section + include ELFTools::Dynamic + + # Get the start address of tags. + # @return [Integer] Start address of tags. + def tag_start + header.sh_offset + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/sections/note_section.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/sections/note_section.rb new file mode 100644 index 0000000000000..111708ef800b5 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/sections/note_section.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require 'elftools/note' +require 'elftools/sections/section' + +module ELFTools + module Sections + # Class of note section. + # Note section records notes + class NoteSection < Section + # Load note related methods. + include ELFTools::Note + + # Address offset of notes start. + # @return [Integer] The offset. + def note_start + header.sh_offset + end + + # The total size of notes in this section. + # @return [Integer] The size. + def note_total_size + header.sh_size + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/sections/null_section.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/sections/null_section.rb new file mode 100644 index 0000000000000..e71172a2be427 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/sections/null_section.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +require 'elftools/sections/section' + +module ELFTools + module Sections + # Class of null section. + # Null section is for specific the end + # of linked list (+sh_link+) between sections. + class NullSection < Section + # Is this a null section? + # @return [Boolean] Yes it is. + def null? + true + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/sections/relocation_section.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/sections/relocation_section.rb new file mode 100644 index 0000000000000..a87780bddf56d --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/sections/relocation_section.rb @@ -0,0 +1,109 @@ +# frozen_string_literal: true + +require 'elftools/constants' +require 'elftools/sections/section' +require 'elftools/structs' + +module ELFTools + module Sections + # Class of note section. + # Note section records notes + class RelocationSection < Section + # Is this relocation a RELA or REL type. + # @return [Boolean] If is RELA. + def rela? + header.sh_type == Constants::SHT_RELA + end + + # Number of relocations in this section. + # @return [Integer] The number. + def num_relocations + header.sh_size / header.sh_entsize + end + + # Acquire the +n+-th relocation, 0-based. + # + # relocations are lazy loaded. + # @param [Integer] n The index. + # @return [ELFTools::Relocation, nil] + # The target relocation. + # If +n+ is out of bound, +nil+ is returned. + def relocation_at(n) + @relocations ||= LazyArray.new(num_relocations, &method(:create_relocation)) + @relocations[n] + end + + # Iterate all relocations. + # + # All relocations are lazy loading, the relocation + # only be created whenever accessing it. + # @yieldparam [ELFTools::Relocation] rel A relocation object. + # @yieldreturn [void] + # @return [Enumerator, Array] + # If block is not given, an enumerator will be returned. + # Otherwise, the whole relocations will be returned. + def each_relocations(&block) + return enum_for(:each_relocations) unless block_given? + + Array.new(num_relocations) do |i| + relocation_at(i).tap(&block) + end + end + + # Simply use {#relocations} to get all relocations. + # @return [Array] + # Whole relocations. + def relocations + each_relocations.to_a + end + + private + + def create_relocation(n) + stream.pos = header.sh_offset + n * header.sh_entsize + klass = rela? ? Structs::ELF_Rela : Structs::ELF_Rel + rel = klass.new(endian: header.class.self_endian, offset: stream.pos) + rel.elf_class = header.elf_class + rel.read(stream) + Relocation.new(rel, stream) + end + end + end + + # A relocation entry. + # + # Can be either a REL or RELA relocation. + # XXX: move this to an independent file? + class Relocation + attr_reader :header # @return [ELFTools::Structs::ELF_Rel, ELFTools::Structs::ELF_Rela] Rel(a) header. + attr_reader :stream # @return [#pos=, #read] Streaming object. + + # Instantiate a {Relocation} object. + def initialize(header, stream) + @header = header + @stream = stream + end + + # +r_info+ contains sym and type, use two methods + # to access them easier. + # @return [Integer] sym infor. + def r_info_sym + header.r_info >> mask_bit + end + alias symbol_index r_info_sym + + # +r_info+ contains sym and type, use two methods + # to access them easier. + # @return [Integer] type infor. + def r_info_type + header.r_info & ((1 << mask_bit) - 1) + end + alias type r_info_type + + private + + def mask_bit + header.elf_class == 32 ? 8 : 32 + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/sections/section.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/sections/section.rb new file mode 100644 index 0000000000000..b0a835cde4971 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/sections/section.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +require 'elftools/constants' +module ELFTools + module Sections + # Base class of sections. + class Section + attr_reader :header # @return [ELFTools::Structs::ELF_Shdr] Section header. + attr_reader :stream # @return [#pos=, #read] Streaming object. + + # Instantiate a {Section} object. + # @param [ELFTools::Structs::ELF_Shdr] header + # The section header object. + # @param [#pos=, #read] stream + # The streaming object for further dump. + # @param [ELFTools::Sections::StrTabSection, Proc] strtab + # The string table object. For fetching section names. + # If +Proc+ if given, it will call at the first + # time access +#name+. + # @param [Method] offset_from_vma + # The method to get offset of file, given virtual memory address. + def initialize(header, stream, offset_from_vma: nil, strtab: nil, **_kwargs) + @header = header + @stream = stream + @strtab = strtab + @offset_from_vma = offset_from_vma + end + + # Return +header.sh_type+ in a simplier way. + # @return [Integer] + # The type, meaning of types are defined in {Constants::SHT}. + def type + header.sh_type.to_i + end + + # Get name of this section. + # @return [String] The name. + def name + @name ||= @strtab.call.name_at(header.sh_name) + end + + # Fetch data of this section. + # @return [String] Data. + def data + stream.pos = header.sh_offset + stream.read(header.sh_size) + end + + # Is this a null section? + # @return [Boolean] No it's not. + def null? + false + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/sections/sections.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/sections/sections.rb new file mode 100644 index 0000000000000..969bf4c9093e8 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/sections/sections.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +# Require this file to load all sections classes. + +require 'elftools/sections/section' + +require 'elftools/sections/dynamic_section' +require 'elftools/sections/note_section' +require 'elftools/sections/null_section' +require 'elftools/sections/relocation_section' +require 'elftools/sections/str_tab_section' +require 'elftools/sections/sym_tab_section' + +module ELFTools + # Defines different types of sections in this module. + module Sections + # Class methods of {Sections::Section}. + class << Section + # Use different class according to +header.sh_type+. + # @param [ELFTools::Structs::ELF_Shdr] header Section header. + # @param [#pos=, #read] stream Streaming object. + # @return [ELFTools::Sections::Section] + # Return object dependes on +header.sh_type+. + def create(header, stream, *args, **kwargs) + klass = case header.sh_type + when Constants::SHT_DYNAMIC then DynamicSection + when Constants::SHT_NULL then NullSection + when Constants::SHT_NOTE then NoteSection + when Constants::SHT_RELA, Constants::SHT_REL then RelocationSection + when Constants::SHT_STRTAB then StrTabSection + when Constants::SHT_SYMTAB, Constants::SHT_DYNSYM then SymTabSection + else Section + end + klass.new(header, stream, *args, **kwargs) + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/sections/str_tab_section.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/sections/str_tab_section.rb new file mode 100644 index 0000000000000..95736190aa0e4 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/sections/str_tab_section.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'elftools/sections/section' +require 'elftools/util' + +module ELFTools + module Sections + # Class of string table section. + # Usually for section .strtab and .dynstr, + # which record names. + class StrTabSection < Section + # Return the section or symbol name. + # @param [Integer] offset + # Usually from +shdr.sh_name+ or +sym.st_name+. + # @return [String] The name without null bytes. + def name_at(offset) + Util.cstring(stream, header.sh_offset + offset) + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/sections/sym_tab_section.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/sections/sym_tab_section.rb new file mode 100644 index 0000000000000..9c5fea04bbe14 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/sections/sym_tab_section.rb @@ -0,0 +1,127 @@ +# frozen_string_literal: true + +require 'elftools/sections/section' + +module ELFTools + module Sections + # Class of symbol table section. + # Usually for section .symtab and .dynsym, + # which will refer to symbols in ELF file. + class SymTabSection < Section + # Instantiate a {SymTabSection} object. + # There's a +section_at+ lambda for {SymTabSection} + # to easily fetch other sections. + # @param [ELFTools::Structs::ELF_Shdr] header + # See {Section#initialize} for more information. + # @param [#pos=, #read] stream + # See {Section#initialize} for more information. + # @param [Proc] section_at + # The method for fetching other sections by index. + # This lambda should be {ELFTools::ELFFile#section_at}. + def initialize(header, stream, section_at: nil, **_kwargs) + @section_at = section_at + # For faster #symbol_by_name + super + end + + # Number of symbols. + # @return [Integer] The number. + # @example + # symtab.num_symbols + # #=> 75 + def num_symbols + header.sh_size / header.sh_entsize + end + + # Acquire the +n+-th symbol, 0-based. + # + # Symbols are lazy loaded. + # @param [Integer] n The index. + # @return [ELFTools::Sections::Symbol, nil] + # The target symbol. + # If +n+ is out of bound, +nil+ is returned. + def symbol_at(n) + @symbols ||= LazyArray.new(num_symbols, &method(:create_symbol)) + @symbols[n] + end + + # Iterate all symbols. + # + # All symbols are lazy loading, the symbol + # only be created whenever accessing it. + # This method is useful for {#symbol_by_name} + # since not all symbols need to be created. + # @yieldparam [ELFTools::Sections::Symbol] sym A symbol object. + # @yieldreturn [void] + # @return [Enumerator, Array] + # If block is not given, an enumerator will be returned. + # Otherwise return array of symbols. + def each_symbols(&block) + return enum_for(:each_symbols) unless block_given? + + Array.new(num_symbols) do |i| + symbol_at(i).tap(&block) + end + end + + # Simply use {#symbols} to get all symbols. + # @return [Array] + # The whole symbols. + def symbols + each_symbols.to_a + end + + # Get symbol by its name. + # @param [String] name + # The name of symbol. + # @return [ELFTools::Sections::Symbol] Desired symbol. + def symbol_by_name(name) + each_symbols.find { |symbol| symbol.name == name } + end + + # Return the symbol string section. + # Lazy loaded. + # @return [ELFTools::Sections::StrTabSection] The string table section. + def symstr + @symstr ||= @section_at.call(header.sh_link) + end + + private + + def create_symbol(n) + stream.pos = header.sh_offset + n * header.sh_entsize + sym = Structs::ELF_sym[header.elf_class].new(endian: header.class.self_endian, offset: stream.pos) + sym.read(stream) + Symbol.new(sym, stream, symstr: method(:symstr)) + end + end + + # Class of symbol. + # + # XXX: Should this class be defined in an independent file? + class Symbol + attr_reader :header # @return [ELFTools::Structs::ELF32_sym, ELFTools::Structs::ELF64_sym] Section header. + attr_reader :stream # @return [#pos=, #read] Streaming object. + + # Instantiate a {ELFTools::Sections::Symbol} object. + # @param [ELFTools::Structs::ELF32_sym, ELFTools::Structs::ELF64_sym] header + # The symbol header. + # @param [#pos=, #read] stream The streaming object. + # @param [ELFTools::Sections::StrTabSection, Proc] symstr + # The symbol string section. + # If +Proc+ is given, it will be called at the first time + # access {Symbol#name}. + def initialize(header, stream, symstr: nil) + @header = header + @stream = stream + @symstr = symstr + end + + # Return the symbol name. + # @return [String] The name. + def name + @name ||= @symstr.call.name_at(header.st_name) + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/segments/dynamic_segment.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/segments/dynamic_segment.rb new file mode 100644 index 0000000000000..cdec0f8e9d61c --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/segments/dynamic_segment.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +require 'elftools/segments/segment' +require 'elftools/dynamic' + +module ELFTools + module Segments + # Class for dynamic table segment. + # + # This class knows how to get the list of dynamic tags. + class DynamicSegment < Segment + include Dynamic # rock! + # Get the start address of tags. + # @return [Integer] Start address of tags. + def tag_start + header.p_offset + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/segments/interp_segment.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/segments/interp_segment.rb new file mode 100644 index 0000000000000..c45a0be7a25aa --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/segments/interp_segment.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +require 'elftools/segments/segment' + +module ELFTools + module Segments + # For DT_INTERP segment, knows how to get path of + # ELF interpreter. + class InterpSegment < Segment + # Get the path of interpreter. + # @return [String] Path to the interpreter. + # @example + # interp_segment.interp_name + # #=> '/lib64/ld-linux-x86-64.so.2' + def interp_name + data[0..-2] # remove last null byte + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/segments/load_segment.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/segments/load_segment.rb new file mode 100644 index 0000000000000..ab41752d1528c --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/segments/load_segment.rb @@ -0,0 +1,91 @@ +# frozen_string_literal: true + +require 'elftools/segments/segment' + +module ELFTools + module Segments + # For DT_LOAD segment. + # Able to query between file offset and virtual memory address. + class LoadSegment < Segment + # Returns the start of this segment. + # @return [Integer] + # The file offset. + def file_head + header.p_offset.to_i + end + + # Returns size in file. + # @return [Integer] + # The size. + def size + header.p_filesz.to_i + end + + # Returns the end of this segment. + # @return [Integer] + # The file offset. + def file_tail + file_head + size + end + + # Returns the start virtual address of this segment. + # @return [Integer] + # The vma. + def mem_head + header.p_vaddr.to_i + end + + # Returns size in memory. + # @return [Integer] + # The size. + def mem_size + header.p_memsz.to_i + end + + # Returns the end virtual address of this segment. + # @return [Integer] + # The vma. + def mem_tail + mem_head + mem_size + end + + # Query if the given file offset located in this segment. + # @param [Integer] offset + # File offset. + # @param [Integer] size + # Size. + # @return [Boolean] + def offset_in?(offset, size = 0) + file_head <= offset && offset + size < file_tail + end + + # Convert file offset into virtual memory address. + # @param [Integer] offset + # File offset. + # @return [Integer] + def offset_to_vma(offset) + # XXX: What if file_head is not aligned with p_vaddr (which is invalid according to ELF spec)? + offset - file_head + header.p_vaddr + end + + # Query if the given virtual memory address located in this segment. + # @param [Integer] vma + # Virtual memory address. + # @param [Integer] size + # Size. + # @return [Boolean] + def vma_in?(vma, size = 0) + vma >= (header.p_vaddr & -header.p_align) && + vma + size <= mem_tail + end + + # Convert virtual memory address into file offset. + # @param [Integer] vma + # Virtual memory address. + # @return [Integer] + def vma_to_offset(vma) + vma - header.p_vaddr + header.p_offset + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/segments/note_segment.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/segments/note_segment.rb new file mode 100644 index 0000000000000..1581bf33c5cb2 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/segments/note_segment.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'elftools/note' +require 'elftools/segments/segment' + +module ELFTools + module Segments + # Class of note segment. + class NoteSegment < Segment + # Load note related methods. + include ELFTools::Note + + # Address offset of notes start. + # @return [Integer] The offset. + def note_start + header.p_offset + end + + # The total size of notes in this segment. + # @return [Integer] The size. + def note_total_size + header.p_filesz + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/segments/segment.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/segments/segment.rb new file mode 100644 index 0000000000000..b575e31cc9b6e --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/segments/segment.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +module ELFTools + module Segments + # Base class of segments. + class Segment + attr_reader :header # @return [ELFTools::Structs::ELF32_Phdr, ELFTools::Structs::ELF64_Phdr] Program header. + attr_reader :stream # @return [#pos=, #read] Streaming object. + + # Instantiate a {Segment} object. + # @param [ELFTools::Structs::ELF32_Phdr, ELFTools::Structs::ELF64_Phdr] header + # Program header. + # @param [#pos=, #read] stream + # Streaming object. + # @param [Method] offset_from_vma + # The method to get offset of file, given virtual memory address. + def initialize(header, stream, offset_from_vma: nil) + @header = header + @stream = stream + @offset_from_vma = offset_from_vma + end + + # Return +header.p_type+ in a simplier way. + # @return [Integer] + # The type, meaning of types are defined in {Constants::PT}. + def type + header.p_type + end + + # The content in this segment. + # @return [String] The content. + def data + stream.pos = header.p_offset + stream.read(header.p_filesz) + end + + # Is this segment readable? + # @return [Boolean] Ture or false. + def readable? + (header.p_flags & 4) == 4 + end + + # Is this segment writable? + # @return [Boolean] Ture or false. + def writable? + (header.p_flags & 2) == 2 + end + + # Is this segment executable? + # @return [Boolean] Ture or false. + def executable? + (header.p_flags & 1) == 1 + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/segments/segments.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/segments/segments.rb new file mode 100644 index 0000000000000..7ca65d9054e38 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/segments/segments.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +# Require this file to load all segment classes. + +require 'elftools/segments/segment' + +require 'elftools/segments/dynamic_segment' +require 'elftools/segments/interp_segment' +require 'elftools/segments/load_segment' +require 'elftools/segments/note_segment' + +module ELFTools + # Module for defining different types of segments. + module Segments + # Class methods of {Segments::Segment}. + class << Segment + # Use different class according to +header.p_type+. + # @param [ELFTools::Structs::ELF32_Phdr, ELFTools::Structs::ELF64_Phdr] header Program header of a segment. + # @param [#pos=, #read] stream Streaming object. + # @return [ELFTools::Segments::Segment] + # Return object dependes on +header.p_type+. + def create(header, stream, *args, **kwargs) + klass = case header.p_type + when Constants::PT_DYNAMIC then DynamicSegment + when Constants::PT_INTERP then InterpSegment + when Constants::PT_LOAD then LoadSegment + when Constants::PT_NOTE then NoteSegment + else Segment + end + klass.new(header, stream, *args, **kwargs) + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/structs.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/structs.rb new file mode 100644 index 0000000000000..c7213bba8d56d --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/structs.rb @@ -0,0 +1,211 @@ +# frozen_string_literal: true + +require 'bindata' + +module ELFTools + # Define ELF related structures in this module. + # + # Structures are fetched from https://github.com/torvalds/linux/blob/master/include/uapi/linux/elf.h. + # Use gem +bindata+ to have these structures support 32/64 bits and little/big endian simultaneously. + module Structs + # The base structure to define common methods. + class ELFStruct < BinData::Record + # DRY. Many fields have different type in different arch. + CHOICE_SIZE_T = { + selection: :elf_class, choices: { 32 => :uint32, 64 => :uint64 } + }.freeze + + attr_accessor :elf_class # @return [Integer] 32 or 64. + attr_accessor :offset # @return [Integer] The file offset of this header. + + # Records which fields have been patched. + # @return [Hash{Integer => Integer}] Patches. + def patches + @patches ||= {} + end + + class << self + # Hooks the constructor. + # + # +BinData::Record+ doesn't allow us to override +#initialize+, so we hack +new+ here. + def new(*args) + # XXX: The better implementation is +new(*args, **kwargs)+, but we can't do this unless bindata changed + # lib/bindata/dsl.rb#override_new_in_class to invoke +new+ with both +args+ and +kwargs+. + kwargs = args.last.is_a?(Hash) ? args.last : {} + offset = kwargs.delete(:offset) + super.tap do |obj| + obj.offset = offset + obj.field_names.each do |f| + m = "#{f}=".to_sym + old_method = obj.singleton_method(m) + obj.singleton_class.send(:undef_method, m) + obj.define_singleton_method(m) do |val| + org = obj.send(f) + obj.patches[org.abs_offset] = ELFStruct.pack(val, org.num_bytes) + old_method.call(val) + end + end + end + end + + # Gets the endianness of current class. + # @return [:little, :big] The endianness. + def self_endian + bindata_name[-2..-1] == 'be' ? :big : :little + end + + # Packs an integer to string. + # @param [Integer] val + # @param [Integer] bytes + # @return [String] + def pack(val, bytes) + raise ArgumentError, "Not supported assign type #{val.class}" unless val.is_a?(Integer) + + number = val & ((1 << (8 * bytes)) - 1) + out = [] + bytes.times do + out << (number & 0xff) + number >>= 8 + end + out = out.pack('C*') + self_endian == :little ? out : out.reverse + end + end + end + + # ELF header structure. + class ELF_Ehdr < ELFStruct + endian :big_and_little + struct :e_ident do + string :magic, read_length: 4 + int8 :ei_class + int8 :ei_data + int8 :ei_version + int8 :ei_osabi + int8 :ei_abiversion + string :ei_padding, read_length: 7 # no use + end + uint16 :e_type + uint16 :e_machine + uint32 :e_version + # entry point + choice :e_entry, **CHOICE_SIZE_T + choice :e_phoff, **CHOICE_SIZE_T + choice :e_shoff, **CHOICE_SIZE_T + uint32 :e_flags + uint16 :e_ehsize # size of this header + uint16 :e_phentsize # size of each segment + uint16 :e_phnum # number of segments + uint16 :e_shentsize # size of each section + uint16 :e_shnum # number of sections + uint16 :e_shstrndx # index of string table section + end + + # Section header structure. + class ELF_Shdr < ELFStruct + endian :big_and_little + uint32 :sh_name + uint32 :sh_type + choice :sh_flags, **CHOICE_SIZE_T + choice :sh_addr, **CHOICE_SIZE_T + choice :sh_offset, **CHOICE_SIZE_T + choice :sh_size, **CHOICE_SIZE_T + uint32 :sh_link + uint32 :sh_info + choice :sh_addralign, **CHOICE_SIZE_T + choice :sh_entsize, **CHOICE_SIZE_T + end + + # Program header structure for 32-bit. + class ELF32_Phdr < ELFStruct + endian :big_and_little + uint32 :p_type + uint32 :p_offset + uint32 :p_vaddr + uint32 :p_paddr + uint32 :p_filesz + uint32 :p_memsz + uint32 :p_flags + uint32 :p_align + end + + # Program header structure for 64-bit. + class ELF64_Phdr < ELFStruct + endian :big_and_little + uint32 :p_type + uint32 :p_flags + uint64 :p_offset + uint64 :p_vaddr + uint64 :p_paddr + uint64 :p_filesz + uint64 :p_memsz + uint64 :p_align + end + + # Gets the class of program header according to bits. + ELF_Phdr = { + 32 => ELF32_Phdr, + 64 => ELF64_Phdr + }.freeze + + # Symbol structure for 32-bit. + class ELF32_sym < ELFStruct + endian :big_and_little + uint32 :st_name + uint32 :st_value + uint32 :st_size + uint8 :st_info + uint8 :st_other + uint16 :st_shndx + end + + # Symbol structure for 64-bit. + class ELF64_sym < ELFStruct + endian :big_and_little + uint32 :st_name # Symbol name, index in string tbl + uint8 :st_info # Type and binding attributes + uint8 :st_other # No defined meaning, 0 + uint16 :st_shndx # Associated section index + uint64 :st_value # Value of the symbol + uint64 :st_size # Associated symbol size + end + + # Get symbol header class according to bits. + ELF_sym = { + 32 => ELF32_sym, + 64 => ELF64_sym + }.freeze + + # Note header. + class ELF_Nhdr < ELFStruct + endian :big_and_little + uint32 :n_namesz # Name size + uint32 :n_descsz # Content size + uint32 :n_type # Content type + end + + # Dynamic tag header. + class ELF_Dyn < ELFStruct + endian :big_and_little + choice :d_tag, selection: :elf_class, choices: { 32 => :int32, 64 => :int64 } + # This is an union type named +d_un+ in original source, + # simplify it to be +d_val+ here. + choice :d_val, **CHOICE_SIZE_T + end + + # Rel header in .rel section. + class ELF_Rel < ELFStruct + endian :big_and_little + choice :r_offset, **CHOICE_SIZE_T + choice :r_info, **CHOICE_SIZE_T + end + + # Rela header in .rela section. + class ELF_Rela < ELFStruct + endian :big_and_little + choice :r_offset, **CHOICE_SIZE_T + choice :r_info, **CHOICE_SIZE_T + choice :r_addend, selection: :elf_class, choices: { 32 => :int32, 64 => :int64 } + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/util.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/util.rb new file mode 100644 index 0000000000000..37727634a1d5b --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/util.rb @@ -0,0 +1,99 @@ +# frozen_string_literal: true + +module ELFTools + # Define some util methods. + module Util + # Class methods. + module ClassMethods + # Round up the number to be mulitple of + # +2**bit+. + # @param [Integer] num Number to be rounded-up. + # @param [Integer] bit How many bit to be aligned. + # @return [Integer] See examples. + # @example + # align(10, 1) #=> 10 + # align(10, 2) #=> 12 + # align(10, 3) #=> 16 + # align(10, 4) #=> 16 + # align(10, 5) #=> 32 + def align(num, bit) + n = 2**bit + return num if (num % n).zero? + + (num + n) & ~(n - 1) + end + + # Fetch the correct value from module +mod+. + # + # See {ELFTools::ELFFile#segment_by_type} for how to + # use this method. + # @param [Module] mod The module defined constant numbers. + # @param [Integer, Symbol, String] val + # Desired value. + # @return [Integer] + # Currently this method always return a value + # from {ELFTools::Constants}. + def to_constant(mod, val) + # Ignore the outest name. + module_name = mod.name.sub('ELFTools::', '') + # if val is an integer, check if exists in mod + if val.is_a?(Integer) + return val if mod.constants.any? { |c| mod.const_get(c) == val } + + raise ArgumentError, "No constants in #{module_name} is #{val}" + end + val = val.to_s.upcase + prefix = module_name.split('::')[-1] + val = prefix + '_' + val unless val.start_with?(prefix) + val = val.to_sym + raise ArgumentError, "No constants in #{module_name} named \"#{val}\"" unless mod.const_defined?(val) + + mod.const_get(val) + end + + # Read from stream until reach a null-byte. + # @param [#pos=, #read] stream Streaming object + # @param [Integer] offset Start from here. + # @return [String] Result string will never contain null byte. + # @example + # Util.cstring(File.open('/bin/cat'), 0) + # #=> "\x7FELF\x02\x01\x01" + def cstring(stream, offset) + stream.pos = offset + # read until "\x00" + ret = '' + loop do + c = stream.read(1) + return nil if c.nil? # reach EOF + break if c == "\x00" + + ret += c + end + ret + end + + # Select objects from enumerator with +.type+ property + # equals to +type+. + # + # Different from naive +Array#select+ is this method + # will yield block whenever find a desired object. + # + # This method is used to simplify the same logic in methods + # {ELFFile#sections_by_type}, {ELFFile#segments_by_type}, etc. + # @param [Enumerator] enum An enumerator for further select. + # @param [Object] type The type you want. + # @return [Array] + # The return value will be objects in +enum+ with attribute + # +.type+ equals to +type+. + def select_by_type(enum, type) + enum.select do |obj| + if obj.type == type + yield obj if block_given? + true + end + end + end + end + extend ClassMethods + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/version.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/version.rb new file mode 100644 index 0000000000000..1108d841fc54b --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/elftools-1.1.2/lib/elftools/version.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +module ELFTools + # Current gem version + VERSION = '1.1.2' +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/patchelf-1.0.0/lib/patchelf.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/patchelf-1.0.0/lib/patchelf.rb new file mode 100644 index 0000000000000..1cb237433a323 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/patchelf-1.0.0/lib/patchelf.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# Main module of patchelf. +# +# @author david942j +module PatchELF +end + +require 'patchelf/patcher' +require 'patchelf/version' diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/patchelf-1.0.0/lib/patchelf/cli.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/patchelf-1.0.0/lib/patchelf/cli.rb new file mode 100644 index 0000000000000..18f82b784bda7 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/patchelf-1.0.0/lib/patchelf/cli.rb @@ -0,0 +1,148 @@ +# frozen_string_literal: true + +require 'optparse' + +require 'patchelf/patcher' +require 'patchelf/version' + +module PatchELF + # For command line interface to parsing arguments. + module CLI + # Name of binary. + SCRIPT_NAME = 'patchelf.rb'.freeze + # CLI usage string. + USAGE = format('Usage: %s FILENAME [OUTPUT_FILE]', SCRIPT_NAME).freeze + + module_function + + # Main method of CLI. + # @param [Array] argv + # Command line arguments. + # @return [void] + # @example + # PatchELF::CLI.work(%w[--help]) + # # usage message to stdout + # PatchELF::CLI.work(%w[--version]) + # # version message to stdout + def work(argv) + @options = { + set: {}, + print: [], + needed: [] + } + return $stdout.puts "PatchELF Version #{PatchELF::VERSION}" if argv.include?('--version') + return $stdout.puts option_parser unless parse(argv) + + # Now the options are (hopefully) valid, let's process the ELF file. + begin + @patcher = PatchELF::Patcher.new(@options[:in_file]) + rescue ELFTools::ELFError, Errno::ENOENT => e + return PatchELF::Logger.error(e.message) + end + patcher.use_rpath! if @options[:force_rpath] + readonly + patch_requests + patcher.save(@options[:out_file]) + end + + private + + def patcher + @patcher + end + + def readonly + @options[:print].uniq.each do |s| + content = patcher.__send__(s) + next if content.nil? + + s = :rpath if @options[:force_rpath] && s == :runpath + $stdout.puts "#{s}: #{Array(content).join(' ')}" + end + end + + def patch_requests + @options[:set].each do |sym, val| + patcher.__send__("#{sym}=".to_sym, val) + end + + @options[:needed].each do |type, val| + patcher.__send__("#{type}_needed".to_sym, *val) + end + end + + def parse(argv) + remain = option_parser.permute(argv) + return false if remain.first.nil? + + @options[:in_file] = remain.first + @options[:out_file] = remain[1] # can be nil + true + end + + def option_parser + @option_parser ||= OptionParser.new do |opts| + opts.banner = USAGE + + opts.on('--print-interpreter', '--pi', 'Show interpreter\'s name.') do + @options[:print] << :interpreter + end + + opts.on('--print-needed', '--pn', 'Show needed libraries specified in DT_NEEDED.') do + @options[:print] << :needed + end + + opts.on('--print-runpath', '--pr', 'Show the path specified in DT_RUNPATH.') do + @options[:print] << :runpath + end + + opts.on('--print-soname', '--ps', 'Show soname specified in DT_SONAME.') do + @options[:print] << :soname + end + + opts.on('--set-interpreter INTERP', '--interp INTERP', 'Set interpreter\'s name.') do |interp| + @options[:set][:interpreter] = interp + end + + opts.on('--set-needed LIB1,LIB2,LIB3', '--needed LIB1,LIB2,LIB3', Array, + 'Set needed libraries, this will remove all existent needed libraries.') do |needs| + @options[:set][:needed] = needs + end + + opts.on('--add-needed LIB', 'Append a new needed library.') do |lib| + @options[:needed] << [:add, lib] + end + + opts.on('--remove-needed LIB', 'Remove a needed library.') do |lib| + @options[:needed] << [:remove, lib] + end + + opts.on('--replace-needed LIB1,LIB2', Array, 'Replace needed library LIB1 as LIB2.') do |libs| + @options[:needed] << [:replace, libs] + end + + opts.on('--set-runpath PATH', '--runpath PATH', 'Set the path of runpath.') do |path| + @options[:set][:runpath] = path + end + + opts.on( + '--force-rpath', + 'According to the ld.so docs, DT_RPATH is obsolete,', + "#{SCRIPT_NAME} will always try to get/set DT_RUNPATH first.", + 'Use this option to force every operations related to runpath (e.g. --runpath)', + 'to consider \'DT_RPATH\' instead of \'DT_RUNPATH\'.' + ) do + @options[:force_rpath] = true + end + + opts.on('--set-soname SONAME', '--so SONAME', 'Set name of a shared library.') do |soname| + @options[:set][:soname] = soname + end + + opts.on('--version', 'Show current gem\'s version.') {} + end + end + + extend self + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/patchelf-1.0.0/lib/patchelf/exceptions.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/patchelf-1.0.0/lib/patchelf/exceptions.rb new file mode 100644 index 0000000000000..771633e261569 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/patchelf-1.0.0/lib/patchelf/exceptions.rb @@ -0,0 +1,9 @@ +# encoding: ascii-8bit +# frozen_string_literal: true + +require 'elftools/exceptions' + +module PatchELF + # Raised on an error during ELF modification. + class PatchError < ELFTools::ELFError; end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/patchelf-1.0.0/lib/patchelf/helper.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/patchelf-1.0.0/lib/patchelf/helper.rb new file mode 100644 index 0000000000000..71c1a3e469072 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/patchelf-1.0.0/lib/patchelf/helper.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +module PatchELF + # Helper methods for internal usage. + module Helper + # The size of one page. + PAGE_SIZE = 0x1000 + + module_function + + # Color codes for pretty print. + COLOR_CODE = { + esc_m: "\e[0m", + info: "\e[38;5;82m", # light green + warn: "\e[38;5;230m", # light yellow + error: "\e[38;5;196m" # heavy red + }.freeze + + # For wrapping string with color codes for prettier inspect. + # @param [String] str + # Content to colorize. + # @param [Symbol] type + # Specify which kind of color to use, valid symbols are defined in {.COLOR_CODE}. + # @return [String] + # String that wrapped with color codes. + def colorize(str, type) + return str unless color_enabled? + + cc = COLOR_CODE + color = cc.key?(type) ? cc[type] : '' + "#{color}#{str.sub(COLOR_CODE[:esc_m], color)}#{cc[:esc_m]}" + end + + # For {#colorize} to decide if need add color codes. + # @return [Boolean] + def color_enabled? + $stderr.tty? + end + + # @param [Integer] val + # @param [Integer] align + # @return [Integer] + # Aligned result. + # @example + # aligndown(0x1234) + # #=> 4096 + # aligndown(0x33, 0x20) + # #=> 32 + # aligndown(0x10, 0x8) + # #=> 16 + def aligndown(val, align = PAGE_SIZE) + val - (val & (align - 1)) + end + + # @param [Integer] val + # @param [Integer] align + # @return [Integer] + # Aligned result. + # @example + # alignup(0x1234) + # #=> 8192 + # alignup(0x33, 0x20) + # #=> 64 + # alignup(0x10, 0x8) + # #=> 16 + def alignup(val, align = PAGE_SIZE) + (val & (align - 1)).zero? ? val : (aligndown(val, align) + align) + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/patchelf-1.0.0/lib/patchelf/logger.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/patchelf-1.0.0/lib/patchelf/logger.rb new file mode 100644 index 0000000000000..ee376f962f131 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/patchelf-1.0.0/lib/patchelf/logger.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'logger' + +require 'patchelf/helper' + +module PatchELF + # A logger for internal usage. + module Logger + module_function + + @logger = ::Logger.new($stderr).tap do |log| + log.formatter = proc do |severity, _datetime, _progname, msg| + "[#{PatchELF::Helper.colorize(severity, severity.downcase.to_sym)}] #{msg}\n" + end + end + + %i[info warn error].each do |sym| + define_method(sym) do |msg| + @logger.__send__(sym, msg) + nil + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/patchelf-1.0.0/lib/patchelf/mm.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/patchelf-1.0.0/lib/patchelf/mm.rb new file mode 100644 index 0000000000000..03eec0bad499c --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/patchelf-1.0.0/lib/patchelf/mm.rb @@ -0,0 +1,186 @@ +# frozen_string_literal: true + +require 'patchelf/helper' + +module PatchELF + # Memory management, provides malloc/free to allocate LOAD segments. + # @private + class MM + attr_reader :extend_size # @return [Integer] The size extended. + attr_reader :threshold # @return [Integer] Where the file start to be extended. + + # Instantiate a {MM} object. + # @param [ELFTools::ELFFile] elf + def initialize(elf) + @elf = elf + @request = [] + end + + # @param [Integer] size + # @return [void] + # @yieldparam [Integer] off + # @yieldparam [Integer] vaddr + # @yieldreturn [void] + # One can only do the following things in the block: + # 1. Set ELF headers' attributes (with ELFTools) + # 2. Invoke {Saver#inline_patch} + def malloc(size, &block) + raise ArgumentError, 'malloc\'s size most be positive.' if size <= 0 + + @request << [size, block] + end + + # Let the malloc / free requests be effective. + # @return [void] + def dispatch! + return if @request.empty? + + @request_size = @request.map(&:first).inject(0, :+) + # The malloc-ed area must be 'rw-' since the dynamic table will be modified during runtime. + # Find all LOADs and calculate their f-gaps and m-gaps. + # We prefer f-gap since it doesn't need move the whole binaries. + # 1. Find if any f-gap has enough size, and one of the LOAD next to it is 'rw-'. + # - expand (forwardlly), only need to change the attribute of LOAD. + # 2. Do 1. again but consider m-gaps instead. + # - expand (forwardlly), need to modify all section headers. + # 3. We have to create a new LOAD, now we need to expand the first LOAD for putting new segment header. + + # First of all we check if there're less than two LOADs. + abnormal_elf('No LOAD segment found, not an executable.') if load_segments.empty? + # TODO: Handle only one LOAD. (be careful if memsz > filesz) + + fgap_method || mgap_method || new_load_method + end + + # Query if extended. + # @return [Boolean] + def extended? + defined?(@threshold) + end + + # Get correct offset after the extension. + # + # @param [Integer] off + # @return [Integer] + # Shifted offset. + def extended_offset(off) + return off unless defined?(@threshold) + return off if off < @threshold + + off + @extend_size + end + + private + + def fgap_method + idx = find_gap { |prv, nxt| nxt.file_head - prv.file_tail } + return false if idx.nil? + + loads = load_segments + # prefer extend backwardly + return extend_backward(loads[idx - 1]) if writable?(loads[idx - 1]) + + extend_forward(loads[idx]) + end + + def extend_backward(seg, size = @request_size) + invoke_callbacks(seg, seg.file_tail) + seg.header.p_filesz += size + seg.header.p_memsz += size + true + end + + def extend_forward(seg, size = @request_size) + seg.header.p_offset -= size + seg.header.p_vaddr -= size + seg.header.p_filesz += size + seg.header.p_memsz += size + invoke_callbacks(seg, seg.file_head) + true + end + + def mgap_method + # | 1 | | 2 | + # | 1 | | 2 | + #=> + # | 1 | | 2 | + # | 1 | | 2 | + idx = find_gap(check_sz: false) { |prv, nxt| PatchELF::Helper.aligndown(nxt.mem_head) - prv.mem_tail } + return false if idx.nil? + + loads = load_segments + @threshold = loads[idx].file_head + @extend_size = PatchELF::Helper.alignup(@request_size) + shift_attributes + # prefer backward than forward + return extend_backward(loads[idx - 1]) if writable?(loads[idx - 1]) + + # note: loads[idx].file_head has been changed in shift_attributes + extend_forward(loads[idx], @extend_size) + end + + def find_gap(check_sz: true) + loads = load_segments + loads.each_with_index do |l, i| + next if i.zero? + next unless writable?(l) || writable?(loads[i - 1]) + + sz = yield(loads[i - 1], l) + abnormal_elf('LOAD segments are out of order.') if check_sz && sz.negative? + next unless sz >= @request_size + + return i + end + nil + end + + # TODO + def new_load_method + raise NotImplementedError + end + + def writable?(seg) + seg.readable? && seg.writable? + end + + # For all attributes >= threshold, += offset + def shift_attributes + # ELFHeader->section_header + # Sections: + # all + # Segments: + # all + # XXX: will be buggy if someday the number of segments can be changed. + + # Bottom-up + @elf.each_sections do |sec| + sec.header.sh_offset += extend_size if sec.header.sh_offset >= threshold + end + @elf.each_segments do |seg| + next unless seg.header.p_offset >= threshold + + seg.header.p_offset += extend_size + # We have to change align of LOAD segment since ld.so checks it. + seg.header.p_align = Helper::PAGE_SIZE if seg.is_a?(ELFTools::Segments::LoadSegment) + end + + @elf.header.e_shoff += extend_size if @elf.header.e_shoff >= threshold + end + + def load_segments + @elf.segments_by_type(:load) + end + + def invoke_callbacks(seg, start) + cur = start + @request.each do |sz, block| + block.call(cur, seg.offset_to_vma(cur)) + cur += sz + end + end + + def abnormal_elf(msg) + raise ArgumentError, msg + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/patchelf-1.0.0/lib/patchelf/patcher.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/patchelf-1.0.0/lib/patchelf/patcher.rb new file mode 100644 index 0000000000000..5d62d69204718 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/patchelf-1.0.0/lib/patchelf/patcher.rb @@ -0,0 +1,215 @@ +# encoding: ascii-8bit +# frozen_string_literal: true + +require 'elftools/elf_file' + +require 'patchelf/exceptions' +require 'patchelf/logger' +require 'patchelf/saver' + +module PatchELF + # Class to handle all patching things. + class Patcher + # @!macro [new] note_apply + # @note This setting will be saved after {#save} being invoked. + + # Instantiate a {Patcher} object. + # @param [String] filename + # Filename of input ELF. + # @param [Boolean] logging + # Whether to use a (stderr-initialized) logger for errors + def initialize(filename, logging: true) + @in_file = filename + @elf = ELFTools::ELFFile.new(File.open(filename)) + @set = {} + @rpath_sym = :runpath + @logging = logging + end + + # @return [String?] + # Get interpreter's name. + # @example + # PatchELF::Patcher.new('/bin/ls').interpreter + # #=> "/lib64/ld-linux-x86-64.so.2" + def interpreter + @set[:interpreter] || interpreter_ + end + + # Set interpreter's name. + # + # If the input ELF has no existent interpreter, + # this method will show a warning and has no effect. + # @param [String] interp + # @macro note_apply + def interpreter=(interp) + return if interpreter_.nil? # will also show warning if there's no interp segment. + + @set[:interpreter] = interp + end + + # Get needed libraries. + # @return [Array] + # @example + # patcher = PatchELF::Patcher.new('/bin/ls') + # patcher.needed + # #=> ["libselinux.so.1", "libc.so.6"] + def needed + @set[:needed] || needed_ + end + + # Set needed libraries. + # @param [Array] needs + # @macro note_apply + def needed=(needs) + @set[:needed] = needs + end + + # Add the needed library. + # @param [String] need + # @return [void] + # @macro note_apply + def add_needed(need) + @set[:needed] ||= needed_ + @set[:needed] << need + end + + # Remove the needed library. + # @param [String] need + # @return [void] + # @macro note_apply + def remove_needed(need) + @set[:needed] ||= needed_ + @set[:needed].delete(need) + end + + # Replace needed library +src+ with +tar+. + # + # @param [String] src + # Library to be replaced. + # @param [String] tar + # Library replace with. + # @return [void] + # @macro note_apply + def replace_needed(src, tar) + @set[:needed] ||= needed_ + @set[:needed].map! { |v| v == src ? tar : v } + end + + # Get the soname of a shared library. + # @return [String?] The name. + # @example + # patcher = PatchELF::Patcher.new('/bin/ls') + # patcher.soname + # # [WARN] Entry DT_SONAME not found, not a shared library? + # #=> nil + # @example + # PatchELF::Patcher.new('/lib/x86_64-linux-gnu/libc.so.6').soname + # #=> "libc.so.6" + def soname + @set[:soname] || soname_ + end + + # Set soname. + # + # If the input ELF is not a shared library with a soname, + # this method will show a warning and has no effect. + # @param [String] name + # @macro note_apply + def soname=(name) + return if soname_.nil? + + @set[:soname] = name + end + + # Get runpath. + # @return [String?] + def runpath + @set[@rpath_sym] || runpath_ + end + + # Set runpath. + # + # If DT_RUNPATH is not presented in the input ELF, + # a new DT_RUNPATH attribute will be inserted into the DYNAMIC segment. + # @param [String] runpath + # @macro note_apply + def runpath=(runpath) + @set[@rpath_sym] = runpath + end + + # Set all operations related to DT_RUNPATH to use DT_RPATH. + # @return [self] + def use_rpath! + @rpath_sym = :rpath + self + end + + # Save the patched ELF as +out_file+. + # @param [String?] out_file + # If +out_file+ is +nil+, the original input file will be modified. + # @return [void] + def save(out_file = nil) + # If nothing is modified, return directly. + return if out_file.nil? && !dirty? + + out_file ||= @in_file + saver = PatchELF::Saver.new(@in_file, out_file, @set) + + saver.save! + end + + private + + def log_or_raise(msg) + raise PatchELF::PatchError, msg unless @logging + + PatchELF::Logger.warn(msg) + end + + def interpreter_ + segment = @elf.segment_by_type(:interp) + return log_or_raise 'No interpreter found.' if segment.nil? + + segment.interp_name + end + + # @return [Array] + def needed_ + segment = dynamic_or_log + return if segment.nil? + + segment.tags_by_type(:needed).map(&:name) + end + + # @return [String?] + def runpath_ + tag_name_or_log(@rpath_sym, "Entry DT_#{@rpath_sym.to_s.upcase} not found.") + end + + # @return [String?] + def soname_ + tag_name_or_log(:soname, 'Entry DT_SONAME not found, not a shared library?') + end + + # @return [Boolean] + def dirty? + @set.any? + end + + def tag_name_or_log(type, log_msg) + segment = dynamic_or_log + return if segment.nil? + + tag = segment.tag_by_type(type) + return log_or_raise log_msg if tag.nil? + + tag.name + end + + def dynamic_or_log + @elf.segment_by_type(:dynamic).tap do |s| + log_or_raise 'DYNAMIC segment not found, might be a statically-linked ELF?' if s.nil? + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/patchelf-1.0.0/lib/patchelf/saver.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/patchelf-1.0.0/lib/patchelf/saver.rb new file mode 100644 index 0000000000000..313a5aa5b1a3d --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/patchelf-1.0.0/lib/patchelf/saver.rb @@ -0,0 +1,285 @@ +# frozen_string_literal: true + +require 'elftools/constants' +require 'elftools/elf_file' +require 'elftools/structs' +require 'elftools/util' +require 'fileutils' + +require 'patchelf/mm' + +module PatchELF + # Internal use only. + # + # For {Patcher} to do patching things and save to file. + # @private + class Saver + attr_reader :in_file # @return [String] Input filename. + attr_reader :out_file # @return [String] Output filename. + + # Instantiate a {Saver} object. + # @param [String] in_file + # @param [String] out_file + # @param [{Symbol => String, Array}] set + def initialize(in_file, out_file, set) + @in_file = in_file + @out_file = out_file + @set = set + # [{Integer => String}] + @inline_patch = {} + @elf = ELFTools::ELFFile.new(File.open(in_file)) + @mm = PatchELF::MM.new(@elf) + @strtab_extend_requests = [] + @append_dyn = [] + end + + # @return [void] + def save! + # In this method we assume all attributes that should exist do exist. + # e.g. DT_INTERP, DT_DYNAMIC. These should have been checked in the patcher. + patch_interpreter + patch_dynamic + + @mm.dispatch! + + FileUtils.cp(in_file, out_file) if out_file != in_file + patch_out(@out_file) + # Let output file have the same permission as input. + FileUtils.chmod(File.stat(in_file).mode, out_file) + end + + private + + def patch_interpreter + return if @set[:interpreter].nil? + + new_interp = @set[:interpreter] + "\x00" + old_interp = @elf.segment_by_type(:interp).interp_name + "\x00" + return if old_interp == new_interp + + # These headers must be found here but not in the proc. + seg_header = @elf.segment_by_type(:interp).header + sec_header = section_header('.interp') + + patch = proc do |off, vaddr| + # Register an inline patching + inline_patch(off, new_interp) + + # The patching feature of ELFTools + seg_header.p_offset = off + seg_header.p_vaddr = seg_header.p_paddr = vaddr + seg_header.p_filesz = seg_header.p_memsz = new_interp.size + + if sec_header + sec_header.sh_offset = off + sec_header.sh_size = new_interp.size + end + end + + if new_interp.size <= old_interp.size + # easy case + patch.call(seg_header.p_offset.to_i, seg_header.p_vaddr.to_i) + else + # hard case, we have to request a new LOAD area + @mm.malloc(new_interp.size, &patch) + end + end + + def patch_dynamic + # We never do inline patching on strtab's string. + # 1. Search if there's useful string exists + # - only need header patching + # 2. Append a new string to the strtab. + # - register strtab extension + dynamic.tags # HACK, force @tags to be defined + patch_soname if @set[:soname] + patch_runpath if @set[:runpath] + patch_runpath(:rpath) if @set[:rpath] + patch_needed if @set[:needed] + malloc_strtab! + expand_dynamic! + end + + def patch_soname + # The tag must exist. + so_tag = dynamic.tag_by_type(:soname) + reg_str_table(@set[:soname]) do |idx| + so_tag.header.d_val = idx + end + end + + def patch_runpath(sym = :runpath) + tag = dynamic.tag_by_type(sym) + tag = tag.nil? ? lazy_dyn(sym) : tag.header + reg_str_table(@set[sym]) do |idx| + tag.d_val = idx + end + end + + # To mark a not-using tag + IGNORE = ELFTools::Constants::DT_LOOS + def patch_needed + original_needs = dynamic.tags_by_type(:needed) + @set[:needed].uniq! + # 3 sets: + # 1. in original and in needs - remain unchanged + # 2. in original but not in needs - remove + # 3. not in original and in needs - append + original_needs.each do |n| + next if @set[:needed].include?(n.name) + + n.header.d_tag = IGNORE # temporarily mark + end + + extra = @set[:needed] - original_needs.map(&:name) + original_needs.each do |n| + break if extra.empty? + next if n.header.d_tag != IGNORE + + n.header.d_tag = ELFTools::Constants::DT_NEEDED + reg_str_table(extra.shift) { |idx| n.header.d_val = idx } + end + return if extra.empty? + + # no spaces, need append + extra.each do |name| + tag = lazy_dyn(:needed) + reg_str_table(name) { |idx| tag.d_val = idx } + end + end + + # Create a temp tag header. + # @return [ELFTools::Structs::ELF_Dyn] + def lazy_dyn(sym) + ELFTools::Structs::ELF_Dyn.new(endian: @elf.endian).tap do |dyn| + @append_dyn << dyn + dyn.elf_class = @elf.elf_class + dyn.d_tag = ELFTools::Util.to_constant(ELFTools::Constants::DT, sym) + end + end + + def expand_dynamic! + return if @append_dyn.empty? + + dyn_sec = section_header('.dynamic') + total = dynamic.tags.map(&:header) + # the last must be a null-tag + total = total[0..-2] + @append_dyn + [total.last] + bytes = total.first.num_bytes * total.size + @mm.malloc(bytes) do |off, vaddr| + inline_patch(off, total.map(&:to_binary_s).join) + dynamic.header.p_offset = off + dynamic.header.p_vaddr = dynamic.header.p_paddr = vaddr + dynamic.header.p_filesz = dynamic.header.p_memsz = bytes + if dyn_sec + dyn_sec.sh_offset = off + dyn_sec.sh_addr = vaddr + dyn_sec.sh_size = bytes + end + end + end + + def malloc_strtab! + return if @strtab_extend_requests.empty? + + strtab = dynamic.tag_by_type(:strtab) + # Process registered requests + need_size = strtab_string.size + @strtab_extend_requests.reduce(0) { |sum, (str, _)| sum + str.size + 1 } + dynstr = section_header('.dynstr') + @mm.malloc(need_size) do |off, vaddr| + new_str = strtab_string + @strtab_extend_requests.map(&:first).join("\x00") + "\x00" + inline_patch(off, new_str) + cur = strtab_string.size + @strtab_extend_requests.each do |str, block| + block.call(cur) + cur += str.size + 1 + end + # Now patching strtab header + strtab.header.d_val = vaddr + # We also need to patch dynstr to let readelf have correct output. + if dynstr + dynstr.sh_size = new_str.size + dynstr.sh_offset = off + dynstr.sh_addr = vaddr + end + end + end + + # @param [String] str + # @yieldparam [Integer] idx + # @yieldreturn [void] + def reg_str_table(str, &block) + idx = strtab_string.index(str + "\x00") + # Request string is already exist + return yield idx if idx + + # Record the request + @strtab_extend_requests << [str, block] + end + + def strtab_string + return @strtab_string if defined?(@strtab_string) + + # TODO: handle no strtab exists.. + offset = @elf.offset_from_vma(dynamic.tag_by_type(:strtab).value) + # This is a little tricky since no length information is stored in the tag. + # We first get the file offset of the string then 'guess' where the end is. + @elf.stream.pos = offset + @strtab_string = +'' + loop do + c = @elf.stream.read(1) + break unless c =~ /\x00|[[:print:]]/ + + @strtab_string << c + end + @strtab_string + end + + # This can only be used for patching interpreter's name + # or set strings in a malloc-ed area. + # i.e. NEVER intend to change the string defined in strtab + def inline_patch(off, str) + @inline_patch[off] = str + end + + # Modify the out_file according to registered patches. + def patch_out(out_file) + File.open(out_file, 'r+') do |f| + if @mm.extended? + original_head = @mm.threshold + extra = {} + # Copy all data after the second load + @elf.stream.pos = original_head + extra[original_head + @mm.extend_size] = @elf.stream.read # read to end + # zero out the 'gap' we created + extra[original_head] = "\x00" * @mm.extend_size + extra.each do |pos, str| + f.pos = pos + f.write(str) + end + end + @elf.patches.each do |pos, str| + f.pos = @mm.extended_offset(pos) + f.write(str) + end + + @inline_patch.each do |pos, str| + f.pos = pos + f.write(str) + end + end + end + + # @return [ELFTools::Sections::Section?] + def section_header(name) + sec = @elf.section_by_name(name) + return if sec.nil? + + sec.header + end + + def dynamic + @dynamic ||= @elf.segment_by_type(:dynamic) + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/patchelf-1.0.0/lib/patchelf/version.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/patchelf-1.0.0/lib/patchelf/version.rb new file mode 100644 index 0000000000000..934c9967d68d9 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/patchelf-1.0.0/lib/patchelf/version.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +module PatchELF + # Current gem version. + VERSION = '1.0.0'.freeze +end