# -*- coding: binary -*-
require_relative "regf"
require_relative "nodekey"

module Rex
module Registry

class Hive
	attr_accessor :root_key, :hive_regf, :hive_name

	def initialize(hivepath)

		hive_blob = open(hivepath, "rb") { |io| io.read }

		@hive_regf = RegfBlock.new(hive_blob)
		return nil if !@hive_regf.root_key_offset

		@root_key = NodeKey.new(hive_blob, 0x1000 + @hive_regf.root_key_offset)
		return nil if !@root_key.lf_record

		keys = []
		root_key.lf_record.children.each do |key|
			keys << key.name
		end

		if keys.include? "LastKnownGoodRecovery"
			@hive_name = "SYSTEM"
		elsif keys.include? "Microsoft"
			@hive_name = "SOFTWARE"
		elsif keys.include? "Environment"
			@hive_name = "NTUSER.DAT"
		elsif keys.include? "SAM"
			@hive_name = "SAM"
		elsif keys.include? "Policy"
			@hive_name = "SECURITY"
		else
			@hive_name = "UNKNOWN"
		end

	end

	def relative_query(path)

		if path == "" || path == "\\"
			return @root_key
		end

		current_child = nil
		paths = path.split("\\")

		return if !@root_key.lf_record

		@root_key.lf_record.children.each do |child|
			next if child.name.downcase != paths[1].downcase

			current_child = child

			if paths.length == 2
				current_child.full_path = path
				return current_child
			end

			2.upto(paths.length) do |i|

				if i == paths.length
					current_child.full_path = path
					return current_child
				else
					if current_child.lf_record && current_child.lf_record.children
						current_child.lf_record.children.each do |c|
							next if c.name.downcase != paths[i].downcase

							current_child = c

							break
						end
					end
				end
			end
		end

		return if !current_child

		current_child.full_path = path
		return current_child
		end

		def value_query(path)
			if path == "" || path == "\\"
			return nil
		end

		paths = path.split("\\")

		return if !@root_key.lf_record

		@root_key.lf_record.children.each do |root_child|
			next if root_child.name.downcase != paths[1].downcase

			current_child = root_child

			if paths.length == 2
				return nil
			end

			2.upto(paths.length - 1) do |i|
				next if !current_child.lf_record

				current_child.lf_record.children.each do |c|
					next if c.name != paths[i]
					current_child = c

					break
				end
			end

			if !current_child.value_list || current_child.value_list.values.length == 0
				return nil
			end

			current_child.value_list.values.each do |value|
				next if value.name.downcase != paths[paths.length - 1].downcase

				value.full_path = path
				return value
			end
		end
	end
end

end
end
