Defend against a peer that sends an invalid message length.
[debian/gnuradio] / grc / base / Param.py
1 """
2 Copyright 2008, 2009 Free Software Foundation, Inc.
3 This file is part of GNU Radio
4
5 GNU Radio Companion is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 GNU Radio Companion is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18 """
19
20 from . import odict
21 from Element import Element
22
23 def _get_keys(lst): return [elem.get_key() for elem in lst]
24 def _get_elem(lst, key):
25         try: return lst[_get_keys(lst).index(key)]
26         except ValueError: raise ValueError, 'Key "%s" not found in %s.'%(key, _get_keys(lst))
27
28 class Option(Element):
29
30         def __init__(self, param, n):
31                 Element.__init__(self, param)
32                 self._name = n.find('name')
33                 self._key = n.find('key')
34                 self._opts = dict()
35                 opts = n.findall('opt')
36                 #test against opts when non enum
37                 try: assert self.get_parent().is_enum() or not opts
38                 except AssertionError: raise Exception, 'Options for non-enum types cannot have sub-options'
39                 #extract opts
40                 for opt in opts:
41                         #separate the key:value
42                         try: key, value = opt.split(':')
43                         except: raise Exception, 'Error separating "%s" into key:value'%opt
44                         #test against repeated keys
45                         try: assert not self._opts.has_key(key)
46                         except AssertionError: raise Exception, 'Key "%s" already exists in option'%key
47                         #store the option
48                         self._opts[key] = value
49
50         def __str__(self): return 'Option %s(%s)'%(self.get_name(), self.get_key())
51         def get_name(self): return self._name
52         def get_key(self): return self._key
53
54         ##############################################
55         # Access Opts
56         ##############################################
57         def get_opt_keys(self): return self._opts.keys()
58         def get_opt(self, key): return self._opts[key]
59         def get_opts(self): return self._opts.values()
60
61 class Param(Element):
62
63         def __init__(self, block, n):
64                 """
65                 Make a new param from nested data.
66                 @param block the parent element
67                 @param n the nested odict
68                 """
69                 #grab the data
70                 self._name = n.find('name')
71                 self._key = n.find('key')
72                 value = n.find('value') or ''
73                 self._type = n.find('type')
74                 self._hide = n.find('hide') or ''
75                 #build the param
76                 Element.__init__(self, block)
77                 #create the Option objects from the n data
78                 self._options = list()
79                 for option in map(lambda o: Option(param=self, n=o), n.findall('option')):
80                         key = option.get_key()
81                         #test against repeated keys
82                         try: assert key not in self.get_option_keys()
83                         except AssertionError: raise Exception, 'Key "%s" already exists in options'%key
84                         #store the option
85                         self.get_options().append(option)
86                 #test the enum options
87                 if self.is_enum():
88                         #test against options with identical keys
89                         try: assert len(set(self.get_option_keys())) == len(self.get_options())
90                         except AssertionError: raise Exception, 'Options keys "%s" are not unique.'%self.get_option_keys()
91                         #test against inconsistent keys in options
92                         opt_keys = self.get_options()[0].get_opt_keys()
93                         for option in self.get_options():
94                                 try: assert set(opt_keys) == set(option.get_opt_keys())
95                                 except AssertionError: raise Exception, 'Opt keys "%s" are not identical across all options.'%opt_keys
96                         #if a value is specified, it must be in the options keys
97                         self._value = value or self.get_option_keys()[0]
98                         try: assert self.get_value() in self.get_option_keys()
99                         except AssertionError: raise Exception, 'The value "%s" is not in the possible values of "%s".'%(self.get_value(), self.get_option_keys())
100                 else: self._value = value or ''
101
102         def validate(self):
103                 """
104                 Validate the param.
105                 The value must be evaluated and type must a possible type.
106                 """
107                 Element.validate(self)
108                 try: assert self.get_type() in self.get_types()
109                 except AssertionError: self.add_error_message('Type "%s" is not a possible type.'%self.get_type())
110
111         def get_evaluated(self): raise NotImplementedError
112
113         def to_code(self):
114                 """
115                 Convert the value to code.
116                 @throw NotImplementedError
117                 """
118                 raise NotImplementedError
119
120         def get_types(self):
121                 """
122                 Get a list of all possible param types.
123                 @throw NotImplementedError
124                 """
125                 raise NotImplementedError
126
127         def get_color(self): return '#FFFFFF'
128         def __str__(self): return 'Param - %s(%s)'%(self.get_name(), self.get_key())
129         def is_param(self): return True
130         def get_name(self): return self._name
131         def get_key(self): return self._key
132         def get_hide(self): return self.get_parent().resolve_dependencies(self._hide).strip()
133
134         def get_value(self):
135                 value = self._value
136                 if self.is_enum() and value not in self.get_option_keys():
137                         value = self.get_option_keys()[0]
138                         self.set_value(value)
139                 return value
140
141         def set_value(self, value): self._value = str(value) #must be a string
142
143         def get_type(self): return self.get_parent().resolve_dependencies(self._type)
144         def is_enum(self): return self._type == 'enum'
145
146         def __repr__(self):
147                 """
148                 Get the repr (nice string format) for this param.
149                 Just return the value (special case enum).
150                 Derived classes can handle complex formatting.
151                 @return the string representation
152                 """
153                 if self.is_enum(): return self.get_option(self.get_value()).get_name()
154                 return self.get_value()
155
156         ##############################################
157         # Access Options
158         ##############################################
159         def get_option_keys(self): return _get_keys(self.get_options())
160         def get_option(self, key): return _get_elem(self.get_options(), key)
161         def get_options(self): return self._options
162
163         ##############################################
164         # Access Opts
165         ##############################################
166         def get_opt_keys(self): return self.get_option(self.get_value()).get_opt_keys()
167         def get_opt(self, key): return self.get_option(self.get_value()).get_opt(key)
168         def get_opts(self): return self.get_option(self.get_value()).get_opts()
169
170         ##############################################
171         ## Import/Export Methods
172         ##############################################
173         def export_data(self):
174                 """
175                 Export this param's key/value.
176                 @return a nested data odict
177                 """
178                 n = odict()
179                 n['key'] = self.get_key()
180                 n['value'] = self.get_value()
181                 return n