From 58f13cfcd279bf61523d327a737b05b85a576b26 Mon Sep 17 00:00:00 2001 From: Mike Auty Date: Mon, 9 Feb 2015 01:57:30 +0000 Subject: [PATCH] Flesh out the config system a little more. --- volatility/framework/config.py | 68 +++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 21 deletions(-) diff --git a/volatility/framework/config.py b/volatility/framework/config.py index c80877b02..329b92326 100644 --- a/volatility/framework/config.py +++ b/volatility/framework/config.py @@ -3,6 +3,7 @@ Created on 7 May 2013 @author: mike """ +from abc import abstractmethod, ABCMeta import re from volatility.framework import validity @@ -20,21 +21,15 @@ class ConfigurationCommonInterface(validity.ValidityRoutines): return self._name -class Option(ConfigurationCommonInterface): +class GenericOption(ConfigurationCommonInterface, ABCMeta): """Class to handle a single specific configuration option""" - def __init__(self, name, option_type, description = None, default = None): + def __init__(self, name, description = None, default = None): """Creates a new option""" ConfigurationCommonInterface.__init__(self, name) - self._type_check(option_type, type) - self._option_type = option_type self._default = default self._description = description - - @property - def option_type(self): - """The data type of the Option, such as string, integer, etc""" - return self._option_type + self._value = None @property def name(self): @@ -46,6 +41,39 @@ class Option(ConfigurationCommonInterface): """A short description of what the Option is designed to affect or achieve.""" return self._description + @property + def value(self): + """Returns the value of the option, or not if it has not yet been set""" + return self._value + + @abstractmethod + def set_value(self, value): + """Populates the value doing typing checking/casting in the process""" + pass + + +class BooleanOption(GenericOption): + def __init__(self, *args, **kwargs): + GenericOption.__init__(*args, **kwargs) + + def set_value(self, value): + self._value = bool(value) + + +class ListOption(GenericOption): + def __init__(self, min_elements, max_elements, element_type, *args, **kwargs): + GenericOption.__init__(self, *args, **kwargs) + self.element_type = self._type_check(element_type, GenericOption) + self.min_elements = min_elements + self.max_elements = max_elements + + def set_value(self, value): + self._type_check(value, list) + all([self._type_check(element) for element in value]) + if not (self.min_elements <= len(value) <= self.max_elements): + raise TypeError("List option provided more or less elements than allowed.") + self._value = value + # TODO: OptionTypes such as choice, list and so on @@ -66,19 +94,17 @@ class Group(ConfigurationCommonInterface): return self._mapping def __setattr__(self, key, value, force = False): - """Type checks values, and only allows those who name matches their key""" - if force: - return super(Group, self).__setattr__(key, value) + """Type checks values, and only allows those whose name matches their key""" + if not force: + if key == 'name': + raise KeyError("Name is a reserved attribute of Configuration items.") - if key == 'name': - raise KeyError("Name is a reserved attribute of Configuration items.") - - self._type_check(value, ConfigurationCommonInterface) - if not re.match('^[A-Za-z][A-Za-z0-9_]*$', value.name): - raise KeyError("Configuration item names must only be lowercase letters.") - if key != value.name: - raise KeyError("Key and value.name must match") - self._mapping.append(key) + self._type_check(value, ConfigurationCommonInterface) + if not re.match('^[A-Za-z][A-Za-z0-9_]*$', value.name): + raise KeyError("Configuration item names must only be lowercase letters.") + if key != value.name: + raise KeyError("Key and value.name must match") + self._mapping.append(key) return super(Group, self).__setattr__(key, value)