lib/ronin/formatting/extensions/binary/string.rb in ronin-support-0.4.1 vs lib/ronin/formatting/extensions/binary/string.rb in ronin-support-0.5.0.rc1
- old
+ new
@@ -15,66 +15,106 @@
#
# You should have received a copy of the GNU Lesser General Public License
# along with Ronin Support. If not, see <http://www.gnu.org/licenses/>.
#
+require 'ronin/formatting/extensions/binary/base64'
require 'ronin/formatting/extensions/binary/integer'
-require 'ronin/formatting/extensions/text'
+require 'ronin/formatting/extensions/text/string'
+require 'ronin/binary/hexdump/parser'
+require 'ronin/binary/template'
-require 'base64'
-require 'enumerator'
-
begin
require 'zlib'
+rescue Gem::LoadError => e
+ raise(e)
rescue ::LoadError
- $stderr.puts "WARNING: Ruby was not compiled with zlib support"
end
class String
+ alias unpack_original unpack
+
#
- # Packs an Integer from a String, which was originally packed for
- # a specific architecture and address-length.
+ # Unpacks the String.
#
+ # @param [String, Array<Symbol>] arguments
+ # The `String#unpack` template or a list of {Ronin::Binary::Template} types.
+ #
+ # @return [Array]
+ # The values unpacked from the String.
+ #
+ # @raise [ArgumentError]
+ # The arguments were not a String or a list of Symbols.
+ #
+ # @example using {Ronin::Binary::Template} types:
+ # "A\0\0\0hello\0".unpack(:uint32_le, :string)
+ # # => [10, "hello"]
+ #
+ # @example using a `String#unpack` template:
+ # "A\0\0\0".unpack('V')
+ # # => 65
+ #
+ # @see http://rubydoc.info/stdlib/core/String:unpack
+ #
+ # @since 0.5.0
+ #
+ # @api public
+ #
+ def unpack(*arguments)
+ case arguments.first
+ when String
+ unpack_original(arguments.first)
+ when Symbol
+ unpack_original(Ronin::Binary::Template.compile(arguments))
+ else
+ raise(ArgumentError,"first argument to String#unpack must be a String or Symbol")
+ end
+ end
+
+ #
+ # Unpacks the String into an Integer.
+ #
# @param [Ronin::Arch, #endian, #address_length, String] arch
# The architecture that the Integer was originally packed with.
#
# @param [Integer] address_length
# The number of bytes to depack.
#
# @return [Integer]
# The depacked Integer.
#
# @raise [ArgumentError]
- # The given `arch` does not respond to the `endian` or
- # `address_length` methods.
+ # The given `arch` does not respond to the `endian` or `address_length`
+ # methods.
#
- # @example using archs other than `Ronin::Arch`.
+ # @example using archs other than `Ronin::Arch`:
# arch = OpenStruct.new(:endian => :little, :address_length => 4)
#
# "A\0\0\0".depack(arch)
# # => 65
#
- # @example using a `Ronin::Arch` arch.
+ # @example using a `Ronin::Arch` arch:
# "A\0\0\0".depack(Arch.i386)
# # => 65
#
- # @example specifying a custom address-length.
+ # @example specifying a custom address-length:
# "A\0".depack(Arch.ppc,2)
# # => 65
#
- # @example using a `String#unpack` template String as the arch.
- # "A\0\0\0".depack('L')
+ # @example using a `String#unpack` template:
+ # "A\0\0\0".depack('V')
# # => 65
#
- # @see http://ruby-doc.org/core/classes/String.html#M000760
+ # @deprecated
+ # Deprecated as of 0.5.0, use {#unpack} instead.
#
# @api public
- #
+ #
def depack(arch,address_length=nil)
if arch.kind_of?(String)
- return self.unpack(arch)
+ return unpack(arch)
end
unless arch.respond_to?(:address_length)
raise(ArgumentError,"first argument to Ineger#pack must respond to address_length")
end
@@ -84,11 +124,11 @@
end
endian = arch.endian.to_sym
address_length ||= arch.address_length
- integer = 0x0
+ integer = 0x0
byte_index = 0
case endian
when :little
mask = lambda { |b| b << (byte_index * 8) }
@@ -126,71 +166,12 @@
#
def hex_escape(options={})
format_bytes(options) { |b| b.hex_escape }
end
- #
- # Unescapes the hex-escaped String.
- #
- # @return [String]
- # The unescaped version of the hex escaped String.
- #
- # @example
- # "\\x68\\x65\\x6c\\x6c\\x6f".hex_unescape
- # # => "hello"
- #
- # @api public
- #
- def hex_unescape
- buffer = ''
- hex_index = 0
- hex_length = length
+ alias hex_unescape unescape
- while (hex_index < hex_length)
- hex_substring = self[hex_index..-1]
-
- if hex_substring =~ /^\\[0-7]{3}/
- buffer << hex_substring[0..3].to_i(8)
- hex_index += 3
- elsif hex_substring =~ /^\\x[0-9a-fA-F]{1,2}/
- hex_substring[2..-1].scan(/^[0-9a-fA-F]{1,2}/) do |hex_byte|
- buffer << hex_byte.to_i(16)
- hex_index += (2 + hex_byte.length)
- end
- elsif hex_substring =~ /^\\./
- escaped_char = hex_substring[1..1]
-
- buffer << case escaped_char
- when '0'
- "\0"
- when 'a'
- "\a"
- when 'b'
- "\b"
- when 't'
- "\t"
- when 'n'
- "\n"
- when 'v'
- "\v"
- when 'f'
- "\f"
- when 'r'
- "\r"
- else
- escaped_char
- end
- hex_index += 2
- else
- buffer << hex_substring[0]
- hex_index += 1
- end
- end
-
- return buffer
- end
-
#
# XOR encodes the String.
#
# @param [Enumerable, Integer] key
# The byte to XOR against each byte in the String.
@@ -248,23 +229,13 @@
# @api public
#
def base64_encode(mode=nil)
case mode
when :strict
- if RUBY_VERSION < '1.9'
- # backported from Ruby 1.9.2
- [self].pack("m")
- else
- Base64.strict_encode64(self)
- end
+ Base64.strict_encode64(self)
when :url, :urlsafe
- if RUBY_VERSION < '1.9'
- # backported from Ruby 1.9.2
- [self].pack("m").tr("+/", "-_")
- else
- Base64.urlsafe_encode64(self)
- end
+ Base64.urlsafe_encode64(self)
else
Base64.encode64(self)
end
end
@@ -291,23 +262,13 @@
# @api public
#
def base64_decode(mode=nil)
case mode
when :strict
- if RUBY_VERSION < '1.9'
- # backported from Ruby 1.9.2
- unpack("m0").first
- else
- Base64.strict_decode64(self)
- end
+ Base64.strict_decode64(self)
when :url, :urlsafe
- if RUBY_VERSION < '1.9'
- # backported from Ruby 1.9.2
- tr("-_", "+/").unpack("m0").first
- else
- Base64.urlsafe_decode64(self)
- end
+ Base64.urlsafe_decode64(self)
else
Base64.decode64(self)
end
end
@@ -360,110 +321,37 @@
# * `:binary`
# * `:octal`
# * `:octal_bytes`
# * `:octal_shorts`
# * `:octal_ints`
- # * `:octal_quads`
+ # * `:octal_quads` (Ruby 1.9 only)
# * `:decimal`
# * `:decimal_bytes`
# * `:decimal_shorts`
# * `:decimal_ints`
- # * `:decimal_quads`
+ # * `:decimal_quads` (Ruby 1.9 only)
# * `:hex`
+ # * `:hex_chars`
# * `:hex_bytes`
# * `:hex_shorts`
# * `:hex_ints`
# * `:hex_quads`
+ # * `:named_chars` (Ruby 1.9 only)
+ # * `:floats`
+ # * `:doubles`
#
+ # @option options [:little, :big, :network] :endian (:little)
+ # The endianness of the words.
+ #
# @option options [Integer] :segment (16)
# The length in bytes of each segment in the hexdump.
#
- # @return [String] The raw-data from the hexdump.
+ # @return [String]
+ # The raw-data from the hexdump.
#
# @api public
#
def unhexdump(options={})
- case (format = options[:format])
- when :od
- address_base = 8
- base = 8
- word_size = 2
- when :hexdump
- address_base = 16
- base = 16
- word_size = 2
- else
- address_base = 16
- base = 16
- word_size = 1
- end
-
- case options[:encoding]
- when :binary
- base = 2
- when :octal, :octal_bytes, :octal_shorts, :octal_ints, :octal_quads
- base = 8
- when :decimal, :decimal_bytes, :decimal_shorts, :decimal_ints, :decimal_quads
- base = 10
- when :hex, :hex_bytes, :hex_shorts, :hex_ints, :hex_quads
- base = 16
- end
-
- case options[:encoding]
- when :binary, :octal_bytes, :decimal_bytes, :hex_bytes
- word_size = 1
- when :octal_shorts, :decimal_shorts, :hex_shorts
- word_size = 2
- when :octal_ints, :decimal_ints, :hex_ints
- word_size = 4
- when :octal_quads, :decimal_quads, :hex_quads
- word_size = 8
- end
-
- current_addr = last_addr = first_addr = nil
- repeated = false
-
- segment_length = (options[:segment] || 16)
- segment = []
- buffer = []
-
- each_line do |line|
- if format == :hexdump
- line = line.gsub(/\s+\|.+\|\s*$/,'')
- end
-
- words = line.split
-
- if words.first == '*'
- repeated = true
- elsif words.length > 0
- current_addr = words.shift.to_i(address_base)
- first_addr ||= current_addr
-
- if repeated
- (((current_addr - last_addr) / segment.length) - 1).times do
- buffer += segment
- end
-
- repeated = false
- end
-
- segment.clear
-
- words.each do |word|
- if (base != 10 && word =~ /^(\\[0abtnvfr\\]|.)$/)
- word.hex_unescape.each_byte { |b| segment << b }
- else
- segment += word.to_i(base).bytes(word_size)
- end
- end
-
- segment = segment[0,segment_length]
- buffer += segment
- last_addr = current_addr
- end
- end
-
- return buffer[0,(last_addr - first_addr)]
+ Ronin::Binary::Hexdump::Parser.new(options).parse(self)
end
end