Package lepl :: Package bin :: Module matchers
[hide private]
[frames] | no frames]

Source Code for Module lepl.bin.matchers

  1   
  2  # The contents of this file are subject to the Mozilla Public License 
  3  # (MPL) Version 1.1 (the "License"); you may not use this file except 
  4  # in compliance with the License. You may obtain a copy of the License 
  5  # at http://www.mozilla.org/MPL/ 
  6  # 
  7  # Software distributed under the License is distributed on an "AS IS" 
  8  # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 
  9  # the License for the specific language governing rights and 
 10  # limitations under the License. 
 11  # 
 12  # The Original Code is LEPL (http://www.acooke.org/lepl) 
 13  # The Initial Developer of the Original Code is Andrew Cooke. 
 14  # Portions created by the Initial Developer are Copyright (C) 2009-2010 
 15  # Andrew Cooke (andrew@acooke.org). All Rights Reserved. 
 16  # 
 17  # Alternatively, the contents of this file may be used under the terms 
 18  # of the LGPL license (the GNU Lesser General Public License, 
 19  # http://www.gnu.org/licenses/lgpl.html), in which case the provisions 
 20  # of the LGPL License are applicable instead of those above. 
 21  # 
 22  # If you wish to allow use of your version of this file only under the 
 23  # terms of the LGPL License and not to allow others to use your version 
 24  # of this file under the MPL, indicate your decision by deleting the 
 25  # provisions above and replace them with the notice and other provisions 
 26  # required by the LGPL License.  If you do not delete the provisions 
 27  # above, a recipient may use your version of this file under either the 
 28  # MPL or the LGPL License. 
 29   
 30  ''' 
 31  Matchers specifically for binary data (most LEPL matchers can be used with 
 32  binary data, but additional support is needed when the matching involves a  
 33  literal comparison or generation of a binary result).  
 34  ''' 
 35   
 36  if bytes is str: 
 37      print('Binary parsing unsupported in this Python version') 
 38  else: 
 39   
 40      from lepl.bin.bits import unpack_length, BitString, STRICT 
 41      from lepl.matchers.support import OperatorMatcher 
 42      from lepl.core.parser import tagged 
 43      from lepl.stream.core import s_next 
44 45 46 # pylint: disable-msg=C0103, R0901, R0904 47 # lepl conventions 48 # pylint: disable-msg=R0201 49 # (allow over-riding in sub-classes) 50 51 - class _Constant(OperatorMatcher):
52 ''' 53 Support class for matching constant values. 54 ''' 55 56 # pylint: disable-msg=E1101 57 # (using _arg to set attributes dynamically) 58
59 - def __init__(self, value):
60 ''' 61 Match a given bit string. 62 63 This is typically not used directly, but via the functions below 64 (which specify a value as integer, bytes, etc). 65 ''' 66 super(_Constant, self).__init__() 67 self._arg(value=value)
68 69 @tagged
70 - def _match(self, stream):
71 ''' 72 Do the matching (return a generator that provides successive 73 (result, stream) tuples). 74 75 Need to be careful here to use only the restricted functionality 76 provided by the stream interface. 77 ''' 78 (value, next_stream) = s_next(stream, count=len(self.value)) 79 if self.value == value: 80 yield ([self.value], next_stream)
81
82 83 - class Const(_Constant):
84 ''' 85 Match a given value, which is parsed as for `BitString.from_int`. 86 ''' 87
88 - def __init__(self, value, length=None):
89 if not isinstance(value, BitString): 90 value = BitString.from_int(value, length) 91 super(Const, self).__init__(value)
92
93 94 - class _Variable(OperatorMatcher):
95 ''' 96 Support class for matching a given number of bits. 97 ''' 98 99 # pylint: disable-msg=E1101 100 # (using _arg to set attributes dynamically) 101
102 - def __init__(self, length):
103 super(_Variable, self).__init__() 104 self._arg(length=unpack_length(length))
105 106 @tagged
107 - def _match(self, stream):
108 ''' 109 Do the matching (return a generator that provides successive 110 (result, stream) tuples). 111 112 Need to be careful here to use only the restricted functionality 113 provided by the stream interface. 114 ''' 115 (value, next_stream) = s_next(stream, count=self.length) 116 yield ([self._convert(value)], next_stream)
117
118 - def _convert(self, bits):
119 ''' 120 By default, just return the bits. 121 ''' 122 return bits
123
124 125 - class _ByteArray(_Variable):
126 ''' 127 Support class for matching a given number of bytes. 128 ''' 129
130 - def __init__(self, length):
131 ''' 132 Match a given number of bytes. 133 ''' 134 if not isinstance(length, int): 135 raise TypeError('Number of bytes must be an integer') 136 super(_ByteArray, self).__init__(length)
137
138 - def _convert(self, bits):
139 ''' 140 Convert from bits to bytes, 141 ''' 142 return bits.to_bytes()
143
144 145 - class BEnd(_Variable):
146 ''' 147 Convert a given number of bits (multiple of 8) to a big-endian number. 148 ''' 149
150 - def __init__(self, length):
151 ''' 152 Match a given number of bits, converting them to a big-endian int. 153 ''' 154 length = unpack_length(length) 155 if length % 8: 156 raise ValueError('Big endian int must a length that is a ' 157 'multiple of 8.') 158 super(BEnd, self).__init__(length)
159
160 - def _convert(self, bits):
161 ''' 162 Convert to int. 163 ''' 164 return bits.to_int(big_endian=True)
165
166 167 - class LEnd(_Variable):
168 ''' 169 Convert a given number of bits to a little-endian number. 170 ''' 171
172 - def _convert(self, bits):
173 ''' 174 Convert to int. 175 ''' 176 return bits.to_int()
177
178 179 - def BitStr(value):
180 ''' 181 Match or read a bit string (to read a value, give the number of bits). 182 ''' 183 if isinstance(value, int): 184 return _Variable(value) 185 else: 186 return _Constant(value)
187
188 189 - def Byte(value=None):
190 ''' 191 Match or read a byte (if a value is given, it must match). 192 ''' 193 if value is None: 194 return BEnd(8) 195 else: 196 return _Constant(BitString.from_byte(value))
197
198 199 - def ByteArray(value):
200 ''' 201 Match or read an array of bytes (to read a value, give the number 202 of bytes). 203 ''' 204 if isinstance(value, int): 205 return _ByteArray(value) 206 else: 207 return _Constant(BitString.from_bytearray(value))
208
209 210 - def _bint(length):
211 ''' 212 Factory method for big-endian values. 213 ''' 214 def matcher(value=None): 215 ''' 216 Generate the matcher, given a value. 217 ''' 218 if value is None: 219 return BEnd(length) 220 else: 221 return _Constant(BitString.from_int(value, length=length, 222 big_endian=True))
223 return matcher 224
225 - def _lint(length):
226 ''' 227 Factory method for little-endian values. 228 ''' 229 def matcher(value=None): 230 ''' 231 Generate the matcher, given a value. 232 ''' 233 if value is None: 234 return LEnd(length) 235 else: 236 return _Constant(BitString.from_int(value, length=length, 237 big_endian=False))
238 return matcher 239 240 241 # pylint: disable-msg=W0105 242 243 BInt16 = _bint(16) 244 ''' 245 Match or read an 16-bit big-endian integer (if a value is given, it 246 must match). 247 ''' 248 249 LInt16 = _lint(16) 250 ''' 251 Match or read an 16-bit little-endian integer (if a value is given, it 252 must match). 253 ''' 254 255 BInt32 = _bint(32) 256 ''' 257 Match or read an 32-bit big-endian integer (if a value is given, it 258 must match). 259 ''' 260 261 LInt32 = _lint(32) 262 ''' 263 Match or read an 32-bit little-endian integer (if a value is given, it 264 must match). 265 ''' 266 267 BInt64 = _bint(64) 268 ''' 269 Match or read an 64-bit big-endian integer (if a value is given, it 270 must match). 271 ''' 272 273 LInt64 = _lint(64) 274 ''' 275 Match or read an 64-bit little-endian integer (if a value is given, it 276 must match). 277 '''
278 279 280 - class _String(_ByteArray):
281 ''' 282 Support class for reading a string. 283 ''' 284 285 # pylint: disable-msg=E1101 286 # (using _arg to set attributes dynamically) 287
288 - def __init__(self, length, encoding=None, errors=STRICT):
289 super(_String, self).__init__(length) 290 self._karg(encoding=encoding) 291 self._karg(errors=errors)
292
293 - def _convert(self, bits):
294 ''' 295 Convert to string. 296 ''' 297 return bits.to_str(encoding=self.encoding, errors=self.errors)
298
299 300 - def String(value, encoding=None, errors=STRICT):
301 ''' 302 Match or read a string (to read a value, give the number of bytes). 303 ''' 304 if isinstance(value, int): 305 return _String(value, encoding=encoding, errors=errors) 306 else: 307 return _Constant(BitString.from_str(value, encoding=encoding, 308 errors=errors))
309