class Arcana::Pattern
Attributes
flags[R]
type[R]
value[R]
Public Class Methods
new(type, value)
click to toggle source
# File lib/arcana.rb, line 133 def initialize(type, value) type, *@flags = type.split("/") @type, *@type_ops = type.split(/(?=[&%+-])/) @value = value end
Public Instance Methods
match?(input)
click to toggle source
# File lib/arcana.rb, line 139 def match?(input) return true if @value == "x" return if !input return if input.eof? flags = @flags.dup case @type when "string", "ustring" flags.delete("b") # force on binary files flags.delete("t") # force on text files flags.delete("w") # FIXME: blanks flags.delete("W") # FIXME: blanks flags.delete("c") # FIXME: case insensitive flags.delete("C") # FIXME: case insensitive if @value.start_with?("!") test_string = parse_string(@value[1..]) input.read(test_string.length) != test_string elsif @value.start_with?("=") test_string = parse_string(@value[1..]) input.read(test_string.length) == test_string else test_string = parse_string(@value) input.read(test_string.length) == test_string end when "byte" match_packed_integer?(input, "c", 1) when "ubyte" match_packed_integer?(input, "C", 1) when "short" match_packed_integer?(input, "s", 2) when "ushort" match_packed_integer?(input, "S", 2) when "long" match_packed_integer?(input, "l", 4) when "ulong" match_packed_integer?(input, "L", 4) when "quad" match_packed_integer?(input, "q", 8) when "uquad" match_packed_integer?(input, "Q", 8) when "leshort" match_packed_integer?(input, "s<", 2) when "uleshort" match_packed_integer?(input, "S<", 2) when "beshort" match_packed_integer?(input, "s>", 2) when "ubeshort" match_packed_integer?(input, "S>", 2) when "lelong" match_packed_integer?(input, "l<", 4) when "ulelong" match_packed_integer?(input, "L<", 4) when "belong" match_packed_integer?(input, "l>", 4) when "ubelong" match_packed_integer?(input, "L>", 4) when "bequad" match_packed_integer?(input, "q>", 8) when "ubequad" match_packed_integer?(input, "Q>", 8) when "lequad" match_packed_integer?(input, "q<", 8) when "ulequad" match_packed_integer?(input, "Q<", 8) when "pstring" return false # FIXME when "guid" return false # FIXME when "der" return false # FIXME when "lestring16" return false # FIXME when "default" return true # FIXME when "clear" return true # FIXME when "name" return false when "use" return false when "offset" match_integer?(input.offset) when "indirect" return false # FIXME when "ledate" return false # FIXME when "bedate" return false # FIXME when "beldate" return false # FIXME when "beqdate" return false # FIXME when "lefloat" return false # FIXME when "regex" if length = flags[0] if length.end_with?("l") # lines length = 8196 elsif length.match?(/\A[0-9]+\z/) length = Integer(length) else return false # FIXME end else length = 8196 end regex = parse_string(@value) # FIXME: seek input to result location input.peek(length).match?(regex) when "search" flags = @flags flags.delete("b") # force on binary files flags.delete("t") # force on text files flags.delete("c") # FIXME: case insensitive flags.delete("C") # FIXME: case insensitive flags = ["1"] if flags.empty? # FIXME: WTF? search_input = input.peek(@value.size + Integer(flags[0]) - 1) flags = flags[1..] value = parse_string(@value) # FIXME: seek input to result location search_input.include?(value) else raise "Unsupported match type: #{@type}" end end
Private Instance Methods
match_integer?(val, bitwidth: 64, match_value: @value)
click to toggle source
# File lib/arcana.rb, line 299 def match_integer?(val, bitwidth: 64, match_value: @value) return true if match_value == "x" return false unless val @type_ops.each do |op| op.match(/\A([&%])?(0x[0-9a-fA-F]+|-?[0-9]+)[lL]?\z/) || raise operand = Integer($2) case $1 when "&" val &= operand when "%" val %= operand end end if match_value.match(/\A([=><!&^])? ?(0x[0-9a-fA-F]+|-?[0-9]+)[lL]?\z/) operator = $1 comparison = Integer($2) if $2.start_with?("0x") && !@type.start_with?("u") # is it signed? if comparison.anybits?(1 << (bitwidth - 1)) comparison = -(((1 << bitwidth) - 1) ^ comparison) - 1 end end if @type_ops.any? comparison &= (1 << bitwidth) - 1 end case operator when "=", nil val == comparison when "<" val < comparison when ">" val > comparison when "!" val != comparison when "&" (val & comparison) == comparison when "^" (val & comparison) == 0 end else binding.irb false # FIXME end end
match_packed_integer?(input, pack_str, length)
click to toggle source
# File lib/arcana.rb, line 292 def match_packed_integer?(input, pack_str, length) input = input.read(length) return false unless input && input.length == length val = input.unpack(pack_str)[0] match_integer?(val, bitwidth: length*8) end
parse_string(value)
click to toggle source
# File lib/arcana.rb, line 276 def parse_string(value) value = value.dup.b value.gsub!(/\\([0-7]{1,3})/) { |match| Integer($1, 8).chr rescue binding.irb } value.gsub!(/\\x([0-9a-fA-F]{2})/) { |match| Integer($1, 16).chr } value.gsub!(/\\(.)/) do case $1 when "n" then "\n" when "t" then "\t" when "f" then "\f" when "r" then "\r" else $1 end end value end