1*134e1779SJakub Wojciech Klama#! /usr/bin/env python 2*134e1779SJakub Wojciech Klama 3*134e1779SJakub Wojciech Klamafrom __future__ import print_function 4*134e1779SJakub Wojciech Klama 5*134e1779SJakub Wojciech Klama#__all__ = ['EncDec', 'EncDecSimple', 'EncDecTyped', 'EncDecA', 6*134e1779SJakub Wojciech Klama# 'SequenceError', 'Sequencer'] 7*134e1779SJakub Wojciech Klama 8*134e1779SJakub Wojciech Klamaimport abc 9*134e1779SJakub Wojciech Klamaimport struct 10*134e1779SJakub Wojciech Klamaimport sys 11*134e1779SJakub Wojciech Klama 12*134e1779SJakub Wojciech Klama_ProtoStruct = { 13*134e1779SJakub Wojciech Klama '1': struct.Struct('<B'), 14*134e1779SJakub Wojciech Klama '2': struct.Struct('<H'), 15*134e1779SJakub Wojciech Klama '4': struct.Struct('<I'), 16*134e1779SJakub Wojciech Klama '8': struct.Struct('<Q'), 17*134e1779SJakub Wojciech Klama '_string_': None, # handled specially 18*134e1779SJakub Wojciech Klama} 19*134e1779SJakub Wojciech Klamafor _i in (1, 2, 4, 8): 20*134e1779SJakub Wojciech Klama _ProtoStruct[_i] = _ProtoStruct[str(_i)] 21*134e1779SJakub Wojciech Klamadel _i 22*134e1779SJakub Wojciech Klama 23*134e1779SJakub Wojciech Klamaclass EncDec(object): 24*134e1779SJakub Wojciech Klama __metaclass__ = abc.ABCMeta 25*134e1779SJakub Wojciech Klama """ 26*134e1779SJakub Wojciech Klama Base class for en/de-coders, which are put into sequencers. 27*134e1779SJakub Wojciech Klama 28*134e1779SJakub Wojciech Klama All have a name and arbitrary user-supplied auxiliary data 29*134e1779SJakub Wojciech Klama (default=None). 30*134e1779SJakub Wojciech Klama 31*134e1779SJakub Wojciech Klama All provide a pack() and unpack(). The pack() function 32*134e1779SJakub Wojciech Klama returns a "bytes" value. This is internally implemented as a 33*134e1779SJakub Wojciech Klama function apack() that returns a list of struct.pack() bytes, 34*134e1779SJakub Wojciech Klama and pack() just joins them up as needed. 35*134e1779SJakub Wojciech Klama 36*134e1779SJakub Wojciech Klama The pack/unpack functions take a dictionary of variable names 37*134e1779SJakub Wojciech Klama and values, and a second dictionary for conditionals, but at 38*134e1779SJakub Wojciech Klama this level conditionals don't apply: they are just being 39*134e1779SJakub Wojciech Klama passed through. Variable names do apply to array encoders 40*134e1779SJakub Wojciech Klama 41*134e1779SJakub Wojciech Klama EncDec also provide b2s() and s2b() static methods, which 42*134e1779SJakub Wojciech Klama convert strings to bytes and vice versa, as reversibly as 43*134e1779SJakub Wojciech Klama possible (using surrogateescape encoding). In Python2 this is 44*134e1779SJakub Wojciech Klama a no-op since the string type *is* the bytes type (<type 45*134e1779SJakub Wojciech Klama 'unicode'>) is the unicode-ized string type). 46*134e1779SJakub Wojciech Klama 47*134e1779SJakub Wojciech Klama EncDec also provides b2u() and u2b() to do conversion to/from 48*134e1779SJakub Wojciech Klama Unicode. 49*134e1779SJakub Wojciech Klama 50*134e1779SJakub Wojciech Klama These are partly for internal use (all strings get converted 51*134e1779SJakub Wojciech Klama to UTF-8 byte sequences when coding a _string_ type) and partly 52*134e1779SJakub Wojciech Klama for doctests, where we just want some py2k/py3k compat hacks. 53*134e1779SJakub Wojciech Klama """ 54*134e1779SJakub Wojciech Klama def __init__(self, name, aux): 55*134e1779SJakub Wojciech Klama self.name = name 56*134e1779SJakub Wojciech Klama self.aux = aux 57*134e1779SJakub Wojciech Klama 58*134e1779SJakub Wojciech Klama @staticmethod 59*134e1779SJakub Wojciech Klama def b2u(byte_sequence): 60*134e1779SJakub Wojciech Klama "transform bytes to unicode" 61*134e1779SJakub Wojciech Klama return byte_sequence.decode('utf-8', 'surrogateescape') 62*134e1779SJakub Wojciech Klama 63*134e1779SJakub Wojciech Klama @staticmethod 64*134e1779SJakub Wojciech Klama def u2b(unicode_sequence): 65*134e1779SJakub Wojciech Klama "transform unicode to bytes" 66*134e1779SJakub Wojciech Klama return unicode_sequence.encode('utf-8', 'surrogateescape') 67*134e1779SJakub Wojciech Klama 68*134e1779SJakub Wojciech Klama if sys.version_info[0] >= 3: 69*134e1779SJakub Wojciech Klama b2s = b2u 70*134e1779SJakub Wojciech Klama @staticmethod 71*134e1779SJakub Wojciech Klama def s2b(string): 72*134e1779SJakub Wojciech Klama "transform string to bytes (leaves raw byte sequence unchanged)" 73*134e1779SJakub Wojciech Klama if isinstance(string, bytes): 74*134e1779SJakub Wojciech Klama return string 75*134e1779SJakub Wojciech Klama return string.encode('utf-8', 'surrogateescape') 76*134e1779SJakub Wojciech Klama else: 77*134e1779SJakub Wojciech Klama @staticmethod 78*134e1779SJakub Wojciech Klama def b2s(byte_sequence): 79*134e1779SJakub Wojciech Klama "transform bytes to string - no-op in python2.7" 80*134e1779SJakub Wojciech Klama return byte_sequence 81*134e1779SJakub Wojciech Klama @staticmethod 82*134e1779SJakub Wojciech Klama def s2b(string): 83*134e1779SJakub Wojciech Klama "transform string or unicode to bytes" 84*134e1779SJakub Wojciech Klama if isinstance(string, unicode): 85*134e1779SJakub Wojciech Klama return string.encode('utf-8', 'surrogateescape') 86*134e1779SJakub Wojciech Klama return string 87*134e1779SJakub Wojciech Klama 88*134e1779SJakub Wojciech Klama def pack(self, vdict, cdict, val): 89*134e1779SJakub Wojciech Klama "encode value <val> into a byte-string" 90*134e1779SJakub Wojciech Klama return b''.join(self.apack(vdict, cdict, val)) 91*134e1779SJakub Wojciech Klama 92*134e1779SJakub Wojciech Klama @abc.abstractmethod 93*134e1779SJakub Wojciech Klama def apack(self, vdict, cdict, val): 94*134e1779SJakub Wojciech Klama "encode value <val> into [bytes1, b2, ..., bN]" 95*134e1779SJakub Wojciech Klama 96*134e1779SJakub Wojciech Klama @abc.abstractmethod 97*134e1779SJakub Wojciech Klama def unpack(self, vdict, cdict, bstring, offset, noerror=False): 98*134e1779SJakub Wojciech Klama "unpack bytes from <bstring> at <offset>" 99*134e1779SJakub Wojciech Klama 100*134e1779SJakub Wojciech Klama 101*134e1779SJakub Wojciech Klamaclass EncDecSimple(EncDec): 102*134e1779SJakub Wojciech Klama r""" 103*134e1779SJakub Wojciech Klama Encode/decode a simple (but named) field. The field is not an 104*134e1779SJakub Wojciech Klama array, which requires using EncDecA, nor a typed object 105*134e1779SJakub Wojciech Klama like a qid or stat instance -- those require a Sequence and 106*134e1779SJakub Wojciech Klama EncDecTyped. 107*134e1779SJakub Wojciech Klama 108*134e1779SJakub Wojciech Klama The format is one of '1'/1, '2'/2, '4'/4, '8'/8, or '_string_'. 109*134e1779SJakub Wojciech Klama 110*134e1779SJakub Wojciech Klama Note: using b2s here is purely a doctest/tetsmod python2/python3 111*134e1779SJakub Wojciech Klama compat hack. The output of e.pack is <type 'bytes'>; b2s 112*134e1779SJakub Wojciech Klama converts it to a string, purely for display purposes. (It might 113*134e1779SJakub Wojciech Klama be better to map py2 output to bytes but they just print as a 114*134e1779SJakub Wojciech Klama string anyway.) In normal use, you should not call b2s here. 115*134e1779SJakub Wojciech Klama 116*134e1779SJakub Wojciech Klama >>> e = EncDecSimple('eggs', 2) 117*134e1779SJakub Wojciech Klama >>> e.b2s(e.pack({}, {}, 0)) 118*134e1779SJakub Wojciech Klama '\x00\x00' 119*134e1779SJakub Wojciech Klama >>> e.b2s(e.pack({}, {}, 256)) 120*134e1779SJakub Wojciech Klama '\x00\x01' 121*134e1779SJakub Wojciech Klama 122*134e1779SJakub Wojciech Klama Values that cannot be packed produce a SequenceError: 123*134e1779SJakub Wojciech Klama 124*134e1779SJakub Wojciech Klama >>> e.pack({}, {}, None) 125*134e1779SJakub Wojciech Klama Traceback (most recent call last): 126*134e1779SJakub Wojciech Klama ... 127*134e1779SJakub Wojciech Klama SequenceError: failed while packing 'eggs'=None 128*134e1779SJakub Wojciech Klama >>> e.pack({}, {}, -1) 129*134e1779SJakub Wojciech Klama Traceback (most recent call last): 130*134e1779SJakub Wojciech Klama ... 131*134e1779SJakub Wojciech Klama SequenceError: failed while packing 'eggs'=-1 132*134e1779SJakub Wojciech Klama 133*134e1779SJakub Wojciech Klama Unpacking both returns a value, and tells how many bytes it 134*134e1779SJakub Wojciech Klama used out of the bytestring or byte-array argument. If there 135*134e1779SJakub Wojciech Klama are not enough bytes remaining at the starting offset, it 136*134e1779SJakub Wojciech Klama raises a SequenceError, unless noerror=True (then unset 137*134e1779SJakub Wojciech Klama values are None) 138*134e1779SJakub Wojciech Klama 139*134e1779SJakub Wojciech Klama >>> e.unpack({}, {}, b'\x00\x01', 0) 140*134e1779SJakub Wojciech Klama (256, 2) 141*134e1779SJakub Wojciech Klama >>> e.unpack({}, {}, b'', 0) 142*134e1779SJakub Wojciech Klama Traceback (most recent call last): 143*134e1779SJakub Wojciech Klama ... 144*134e1779SJakub Wojciech Klama SequenceError: out of data while unpacking 'eggs' 145*134e1779SJakub Wojciech Klama >>> e.unpack({}, {}, b'', 0, noerror=True) 146*134e1779SJakub Wojciech Klama (None, 2) 147*134e1779SJakub Wojciech Klama 148*134e1779SJakub Wojciech Klama Note that strings can be provided as regular strings, byte 149*134e1779SJakub Wojciech Klama strings (same as regular strings in py2k), or Unicode strings 150*134e1779SJakub Wojciech Klama (same as regular strings in py3k). Unicode strings will be 151*134e1779SJakub Wojciech Klama converted to UTF-8 before being packed. Since this leaves 152*134e1779SJakub Wojciech Klama 7-bit characters alone, these examples work in both py2k and 153*134e1779SJakub Wojciech Klama py3k. (Note: the UTF-8 encoding of u'\u1234' is 154*134e1779SJakub Wojciech Klama '\0xe1\0x88\0xb4' or 225, 136, 180. The b2i trick below is 155*134e1779SJakub Wojciech Klama another py2k vs py3k special case just for doctests: py2k 156*134e1779SJakub Wojciech Klama tries to display the utf-8 encoded data as a string.) 157*134e1779SJakub Wojciech Klama 158*134e1779SJakub Wojciech Klama >>> e = EncDecSimple('spam', '_string_') 159*134e1779SJakub Wojciech Klama >>> e.b2s(e.pack({}, {}, 'p3=unicode,p2=bytes')) 160*134e1779SJakub Wojciech Klama '\x13\x00p3=unicode,p2=bytes' 161*134e1779SJakub Wojciech Klama 162*134e1779SJakub Wojciech Klama >>> e.b2s(e.pack({}, {}, b'bytes')) 163*134e1779SJakub Wojciech Klama '\x05\x00bytes' 164*134e1779SJakub Wojciech Klama 165*134e1779SJakub Wojciech Klama >>> import sys 166*134e1779SJakub Wojciech Klama >>> ispy3k = sys.version_info[0] >= 3 167*134e1779SJakub Wojciech Klama 168*134e1779SJakub Wojciech Klama >>> b2i = lambda x: x if ispy3k else ord(x) 169*134e1779SJakub Wojciech Klama >>> [b2i(x) for x in e.pack({}, {}, u'\u1234')] 170*134e1779SJakub Wojciech Klama [3, 0, 225, 136, 180] 171*134e1779SJakub Wojciech Klama 172*134e1779SJakub Wojciech Klama The byte length of the utf-8 data cannot exceed 65535 since 173*134e1779SJakub Wojciech Klama the encoding has the length as a 2-byte field (a la the 174*134e1779SJakub Wojciech Klama encoding for 'eggs' here). A too-long string produces 175*134e1779SJakub Wojciech Klama a SequenceError as well. 176*134e1779SJakub Wojciech Klama 177*134e1779SJakub Wojciech Klama >>> e.pack({}, {}, 16384 * 'spam') 178*134e1779SJakub Wojciech Klama Traceback (most recent call last): 179*134e1779SJakub Wojciech Klama ... 180*134e1779SJakub Wojciech Klama SequenceError: string too long (len=65536) while packing 'spam' 181*134e1779SJakub Wojciech Klama 182*134e1779SJakub Wojciech Klama Unpacking strings produces byte arrays. (Of course, 183*134e1779SJakub Wojciech Klama in py2k these are also known as <type 'str'>.) 184*134e1779SJakub Wojciech Klama 185*134e1779SJakub Wojciech Klama >>> unpacked = e.unpack({}, {}, b'\x04\x00data', 0) 186*134e1779SJakub Wojciech Klama >>> etype = bytes if ispy3k else str 187*134e1779SJakub Wojciech Klama >>> print(isinstance(unpacked[0], etype)) 188*134e1779SJakub Wojciech Klama True 189*134e1779SJakub Wojciech Klama >>> e.b2s(unpacked[0]) 190*134e1779SJakub Wojciech Klama 'data' 191*134e1779SJakub Wojciech Klama >>> unpacked[1] 192*134e1779SJakub Wojciech Klama 6 193*134e1779SJakub Wojciech Klama 194*134e1779SJakub Wojciech Klama You may use e.b2s() to conver them to unicode strings in py3k, 195*134e1779SJakub Wojciech Klama or you may set e.autob2s. This still only really does 196*134e1779SJakub Wojciech Klama anything in py3k, since py2k strings *are* bytes, so it's 197*134e1779SJakub Wojciech Klama really just intended for doctest purposes (see EncDecA): 198*134e1779SJakub Wojciech Klama 199*134e1779SJakub Wojciech Klama >>> e.autob2s = True 200*134e1779SJakub Wojciech Klama >>> e.unpack({}, {}, b'\x07\x00stringy', 0) 201*134e1779SJakub Wojciech Klama ('stringy', 9) 202*134e1779SJakub Wojciech Klama """ 203*134e1779SJakub Wojciech Klama def __init__(self, name, fmt, aux=None): 204*134e1779SJakub Wojciech Klama super(EncDecSimple, self).__init__(name, aux) 205*134e1779SJakub Wojciech Klama self.fmt = fmt 206*134e1779SJakub Wojciech Klama self.struct = _ProtoStruct[fmt] 207*134e1779SJakub Wojciech Klama self.autob2s = False 208*134e1779SJakub Wojciech Klama 209*134e1779SJakub Wojciech Klama def __repr__(self): 210*134e1779SJakub Wojciech Klama if self.aux is None: 211*134e1779SJakub Wojciech Klama return '{0}({1!r}, {2!r})'.format(self.__class__.__name__, 212*134e1779SJakub Wojciech Klama self.name, self.fmt) 213*134e1779SJakub Wojciech Klama return '{0}({1!r}, {2!r}, {3!r})'.format(self.__class__.__name__, 214*134e1779SJakub Wojciech Klama self.name, self.fmt, self.aux) 215*134e1779SJakub Wojciech Klama 216*134e1779SJakub Wojciech Klama __str__ = __repr__ 217*134e1779SJakub Wojciech Klama 218*134e1779SJakub Wojciech Klama def apack(self, vdict, cdict, val): 219*134e1779SJakub Wojciech Klama "encode a value" 220*134e1779SJakub Wojciech Klama try: 221*134e1779SJakub Wojciech Klama if self.struct: 222*134e1779SJakub Wojciech Klama return [self.struct.pack(val)] 223*134e1779SJakub Wojciech Klama sval = self.s2b(val) 224*134e1779SJakub Wojciech Klama if len(sval) > 65535: 225*134e1779SJakub Wojciech Klama raise SequenceError('string too long (len={0:d}) ' 226*134e1779SJakub Wojciech Klama 'while packing {1!r}'.format(len(sval), self.name)) 227*134e1779SJakub Wojciech Klama return [EncDecSimple.string_len.pack(len(sval)), sval] 228*134e1779SJakub Wojciech Klama # Include AttributeError in case someone tries to, e.g., 229*134e1779SJakub Wojciech Klama # pack name=None and self.s2b() tries to use .encode on it. 230*134e1779SJakub Wojciech Klama except (struct.error, AttributeError): 231*134e1779SJakub Wojciech Klama raise SequenceError('failed ' 232*134e1779SJakub Wojciech Klama 'while packing {0!r}={1!r}'.format(self.name, val)) 233*134e1779SJakub Wojciech Klama 234*134e1779SJakub Wojciech Klama def _unpack1(self, via, bstring, offset, noerror): 235*134e1779SJakub Wojciech Klama "internal function to unpack single item" 236*134e1779SJakub Wojciech Klama try: 237*134e1779SJakub Wojciech Klama tup = via.unpack_from(bstring, offset) 238*134e1779SJakub Wojciech Klama except struct.error as err: 239*134e1779SJakub Wojciech Klama if 'unpack_from requires a buffer of at least' in str(err): 240*134e1779SJakub Wojciech Klama if noerror: 241*134e1779SJakub Wojciech Klama return None, offset + via.size 242*134e1779SJakub Wojciech Klama raise SequenceError('out of data ' 243*134e1779SJakub Wojciech Klama 'while unpacking {0!r}'.format(self.name)) 244*134e1779SJakub Wojciech Klama # not clear what to do here if noerror 245*134e1779SJakub Wojciech Klama raise SequenceError('failed ' 246*134e1779SJakub Wojciech Klama 'while unpacking {0!r}'.format(self.name)) 247*134e1779SJakub Wojciech Klama assert len(tup) == 1 248*134e1779SJakub Wojciech Klama return tup[0], offset + via.size 249*134e1779SJakub Wojciech Klama 250*134e1779SJakub Wojciech Klama def unpack(self, vdict, cdict, bstring, offset, noerror=False): 251*134e1779SJakub Wojciech Klama "decode a value; return the value and the new offset" 252*134e1779SJakub Wojciech Klama if self.struct: 253*134e1779SJakub Wojciech Klama return self._unpack1(self.struct, bstring, offset, noerror) 254*134e1779SJakub Wojciech Klama slen, offset = self._unpack1(EncDecSimple.string_len, bstring, offset, 255*134e1779SJakub Wojciech Klama noerror) 256*134e1779SJakub Wojciech Klama if slen is None: 257*134e1779SJakub Wojciech Klama return None, offset 258*134e1779SJakub Wojciech Klama nexto = offset + slen 259*134e1779SJakub Wojciech Klama if len(bstring) < nexto: 260*134e1779SJakub Wojciech Klama if noerror: 261*134e1779SJakub Wojciech Klama val = None 262*134e1779SJakub Wojciech Klama else: 263*134e1779SJakub Wojciech Klama raise SequenceError('out of data ' 264*134e1779SJakub Wojciech Klama 'while unpacking {0!r}'.format(self.name)) 265*134e1779SJakub Wojciech Klama else: 266*134e1779SJakub Wojciech Klama val = bstring[offset:nexto] 267*134e1779SJakub Wojciech Klama if self.autob2s: 268*134e1779SJakub Wojciech Klama val = self.b2s(val) 269*134e1779SJakub Wojciech Klama return val, nexto 270*134e1779SJakub Wojciech Klama 271*134e1779SJakub Wojciech Klama# string length: 2 byte unsigned field 272*134e1779SJakub Wojciech KlamaEncDecSimple.string_len = _ProtoStruct[2] 273*134e1779SJakub Wojciech Klama 274*134e1779SJakub Wojciech Klamaclass EncDecTyped(EncDec): 275*134e1779SJakub Wojciech Klama r""" 276*134e1779SJakub Wojciech Klama EncDec for typed objects (which are build from PFODs, which are 277*134e1779SJakub Wojciech Klama a sneaky class variant of OrderedDict similar to namedtuple). 278*134e1779SJakub Wojciech Klama 279*134e1779SJakub Wojciech Klama Calling the klass() function with no arguments must create an 280*134e1779SJakub Wojciech Klama instance with all-None members. 281*134e1779SJakub Wojciech Klama 282*134e1779SJakub Wojciech Klama We also require a Sequencer to pack and unpack the members of 283*134e1779SJakub Wojciech Klama the underlying pfod. 284*134e1779SJakub Wojciech Klama 285*134e1779SJakub Wojciech Klama >>> qid_s = Sequencer('qid') 286*134e1779SJakub Wojciech Klama >>> qid_s.append_encdec(None, EncDecSimple('type', 1)) 287*134e1779SJakub Wojciech Klama >>> qid_s.append_encdec(None, EncDecSimple('version', 4)) 288*134e1779SJakub Wojciech Klama >>> qid_s.append_encdec(None, EncDecSimple('path', 8)) 289*134e1779SJakub Wojciech Klama >>> len(qid_s) 290*134e1779SJakub Wojciech Klama 3 291*134e1779SJakub Wojciech Klama 292*134e1779SJakub Wojciech Klama >>> from pfod import pfod 293*134e1779SJakub Wojciech Klama >>> qid = pfod('qid', ['type', 'version', 'path']) 294*134e1779SJakub Wojciech Klama >>> len(qid._fields) 295*134e1779SJakub Wojciech Klama 3 296*134e1779SJakub Wojciech Klama >>> qid_inst = qid(1, 2, 3) 297*134e1779SJakub Wojciech Klama >>> qid_inst 298*134e1779SJakub Wojciech Klama qid(type=1, version=2, path=3) 299*134e1779SJakub Wojciech Klama 300*134e1779SJakub Wojciech Klama >>> e = EncDecTyped(qid, 'aqid', qid_s) 301*134e1779SJakub Wojciech Klama >>> e.b2s(e.pack({}, {}, qid_inst)) 302*134e1779SJakub Wojciech Klama '\x01\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00' 303*134e1779SJakub Wojciech Klama >>> e.unpack({}, {}, 304*134e1779SJakub Wojciech Klama ... b'\x01\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00', 0) 305*134e1779SJakub Wojciech Klama (qid(type=1, version=2, path=3), 13) 306*134e1779SJakub Wojciech Klama 307*134e1779SJakub Wojciech Klama If an EncDecTyped instance has a conditional sequencer, note 308*134e1779SJakub Wojciech Klama that unpacking will leave un-selected items set to None (see 309*134e1779SJakub Wojciech Klama the Sequencer example below): 310*134e1779SJakub Wojciech Klama 311*134e1779SJakub Wojciech Klama >>> breakfast = pfod('breakfast', 'eggs spam ham') 312*134e1779SJakub Wojciech Klama >>> breakfast() 313*134e1779SJakub Wojciech Klama breakfast(eggs=None, spam=None, ham=None) 314*134e1779SJakub Wojciech Klama >>> bfseq = Sequencer('breakfast') 315*134e1779SJakub Wojciech Klama >>> bfseq.append_encdec(None, EncDecSimple('eggs', 1)) 316*134e1779SJakub Wojciech Klama >>> bfseq.append_encdec('yuck', EncDecSimple('spam', 1)) 317*134e1779SJakub Wojciech Klama >>> bfseq.append_encdec(None, EncDecSimple('ham', 1)) 318*134e1779SJakub Wojciech Klama >>> e = EncDecTyped(breakfast, 'bfname', bfseq) 319*134e1779SJakub Wojciech Klama >>> e.unpack({}, {'yuck': False}, b'\x02\x01\x04', 0) 320*134e1779SJakub Wojciech Klama (breakfast(eggs=2, spam=None, ham=1), 2) 321*134e1779SJakub Wojciech Klama 322*134e1779SJakub Wojciech Klama This used just two of the three bytes: eggs=2, ham=1. 323*134e1779SJakub Wojciech Klama 324*134e1779SJakub Wojciech Klama >>> e.unpack({}, {'yuck': True}, b'\x02\x01\x04', 0) 325*134e1779SJakub Wojciech Klama (breakfast(eggs=2, spam=1, ham=4), 3) 326*134e1779SJakub Wojciech Klama 327*134e1779SJakub Wojciech Klama This used the third byte, so ham=4. 328*134e1779SJakub Wojciech Klama """ 329*134e1779SJakub Wojciech Klama def __init__(self, klass, name, sequence, aux=None): 330*134e1779SJakub Wojciech Klama assert len(sequence) == len(klass()._fields) # temporary 331*134e1779SJakub Wojciech Klama super(EncDecTyped, self).__init__(name, aux) 332*134e1779SJakub Wojciech Klama self.klass = klass 333*134e1779SJakub Wojciech Klama self.name = name 334*134e1779SJakub Wojciech Klama self.sequence = sequence 335*134e1779SJakub Wojciech Klama 336*134e1779SJakub Wojciech Klama def __repr__(self): 337*134e1779SJakub Wojciech Klama if self.aux is None: 338*134e1779SJakub Wojciech Klama return '{0}({1!r}, {2!r}, {3!r})'.format(self.__class__.__name__, 339*134e1779SJakub Wojciech Klama self.klass, self.name, self.sequence) 340*134e1779SJakub Wojciech Klama return '{0}({1!r}, {2!r}, {3!r}, {4!r})'.format(self.__class__.__name__, 341*134e1779SJakub Wojciech Klama self.klass, self.name, self.sequence, self.aux) 342*134e1779SJakub Wojciech Klama 343*134e1779SJakub Wojciech Klama __str__ = __repr__ 344*134e1779SJakub Wojciech Klama 345*134e1779SJakub Wojciech Klama def apack(self, vdict, cdict, val): 346*134e1779SJakub Wojciech Klama """ 347*134e1779SJakub Wojciech Klama Pack each of our instance variables. 348*134e1779SJakub Wojciech Klama 349*134e1779SJakub Wojciech Klama Note that some packing may be conditional. 350*134e1779SJakub Wojciech Klama """ 351*134e1779SJakub Wojciech Klama return self.sequence.apack(val, cdict) 352*134e1779SJakub Wojciech Klama 353*134e1779SJakub Wojciech Klama def unpack(self, vdict, cdict, bstring, offset, noerror=False): 354*134e1779SJakub Wojciech Klama """ 355*134e1779SJakub Wojciech Klama Unpack each instance variable, into a new object of 356*134e1779SJakub Wojciech Klama self.klass. Return the new instance and new offset. 357*134e1779SJakub Wojciech Klama 358*134e1779SJakub Wojciech Klama Note that some unpacking may be conditional. 359*134e1779SJakub Wojciech Klama """ 360*134e1779SJakub Wojciech Klama obj = self.klass() 361*134e1779SJakub Wojciech Klama offset = self.sequence.unpack_from(obj, cdict, bstring, offset, noerror) 362*134e1779SJakub Wojciech Klama return obj, offset 363*134e1779SJakub Wojciech Klama 364*134e1779SJakub Wojciech Klamaclass EncDecA(EncDec): 365*134e1779SJakub Wojciech Klama r""" 366*134e1779SJakub Wojciech Klama EncDec for arrays (repeated objects). 367*134e1779SJakub Wojciech Klama 368*134e1779SJakub Wojciech Klama We take the name of repeat count variable, and a sub-coder 369*134e1779SJakub Wojciech Klama (Sequencer instance). For instance, we can en/de-code 370*134e1779SJakub Wojciech Klama repeat='nwname' copies of name='wname', or nwname of 371*134e1779SJakub Wojciech Klama name='wqid', in a Twalk en/de-code. 372*134e1779SJakub Wojciech Klama 373*134e1779SJakub Wojciech Klama Note that we don't pack or unpack the repeat count itself -- 374*134e1779SJakub Wojciech Klama that must be done by higher level code. We just get its value 375*134e1779SJakub Wojciech Klama from vdict. 376*134e1779SJakub Wojciech Klama 377*134e1779SJakub Wojciech Klama >>> subcode = EncDecSimple('wname', '_string_') 378*134e1779SJakub Wojciech Klama >>> e = EncDecA('nwname', 'wname', subcode) 379*134e1779SJakub Wojciech Klama >>> e.b2s(e.pack({'nwname': 2}, {}, ['A', 'BC'])) 380*134e1779SJakub Wojciech Klama '\x01\x00A\x02\x00BC' 381*134e1779SJakub Wojciech Klama 382*134e1779SJakub Wojciech Klama >>> subcode.autob2s = True # so that A and BC decode to py3k str 383*134e1779SJakub Wojciech Klama >>> e.unpack({'nwname': 2}, {}, b'\x01\x00A\x02\x00BC', 0) 384*134e1779SJakub Wojciech Klama (['A', 'BC'], 7) 385*134e1779SJakub Wojciech Klama 386*134e1779SJakub Wojciech Klama When using noerror, the first sub-item that fails to decode 387*134e1779SJakub Wojciech Klama completely starts the None-s. Strings whose length fails to 388*134e1779SJakub Wojciech Klama decode are assumed to be zero bytes long as well, for the 389*134e1779SJakub Wojciech Klama purpose of showing the expected packet length: 390*134e1779SJakub Wojciech Klama 391*134e1779SJakub Wojciech Klama >>> e.unpack({'nwname': 2}, {}, b'\x01\x00A\x02\x00', 0, noerror=True) 392*134e1779SJakub Wojciech Klama (['A', None], 7) 393*134e1779SJakub Wojciech Klama >>> e.unpack({'nwname': 2}, {}, b'\x01\x00A\x02', 0, noerror=True) 394*134e1779SJakub Wojciech Klama (['A', None], 5) 395*134e1779SJakub Wojciech Klama >>> e.unpack({'nwname': 3}, {}, b'\x01\x00A\x02', 0, noerror=True) 396*134e1779SJakub Wojciech Klama (['A', None, None], 7) 397*134e1779SJakub Wojciech Klama 398*134e1779SJakub Wojciech Klama As a special case, supplying None for the sub-coder 399*134e1779SJakub Wojciech Klama makes the repeated item pack or unpack a simple byte 400*134e1779SJakub Wojciech Klama string. (Note that autob2s is not supported here.) 401*134e1779SJakub Wojciech Klama A too-short byte string is simply truncated! 402*134e1779SJakub Wojciech Klama 403*134e1779SJakub Wojciech Klama >>> e = EncDecA('count', 'data', None) 404*134e1779SJakub Wojciech Klama >>> e.b2s(e.pack({'count': 5}, {}, b'12345')) 405*134e1779SJakub Wojciech Klama '12345' 406*134e1779SJakub Wojciech Klama >>> x = list(e.unpack({'count': 3}, {}, b'123', 0)) 407*134e1779SJakub Wojciech Klama >>> x[0] = e.b2s(x[0]) 408*134e1779SJakub Wojciech Klama >>> x 409*134e1779SJakub Wojciech Klama ['123', 3] 410*134e1779SJakub Wojciech Klama >>> x = list(e.unpack({'count': 3}, {}, b'12', 0, noerror=True)) 411*134e1779SJakub Wojciech Klama >>> x[0] = e.b2s(x[0]) 412*134e1779SJakub Wojciech Klama >>> x 413*134e1779SJakub Wojciech Klama ['12', 3] 414*134e1779SJakub Wojciech Klama """ 415*134e1779SJakub Wojciech Klama def __init__(self, repeat, name, sub, aux=None): 416*134e1779SJakub Wojciech Klama super(EncDecA, self).__init__(name, aux) 417*134e1779SJakub Wojciech Klama self.repeat = repeat 418*134e1779SJakub Wojciech Klama self.name = name 419*134e1779SJakub Wojciech Klama self.sub = sub 420*134e1779SJakub Wojciech Klama 421*134e1779SJakub Wojciech Klama def __repr__(self): 422*134e1779SJakub Wojciech Klama if self.aux is None: 423*134e1779SJakub Wojciech Klama return '{0}({1!r}, {2!r}, {3!r})'.format(self.__class__.__name__, 424*134e1779SJakub Wojciech Klama self.repeat, self.name, self.sub) 425*134e1779SJakub Wojciech Klama return '{0}({1!r}, {2!r}, {3!r}, {4!r})'.format(self.__class__.__name__, 426*134e1779SJakub Wojciech Klama self.repeat, self.name, self.sub, self.aux) 427*134e1779SJakub Wojciech Klama 428*134e1779SJakub Wojciech Klama __str__ = __repr__ 429*134e1779SJakub Wojciech Klama 430*134e1779SJakub Wojciech Klama def apack(self, vdict, cdict, val): 431*134e1779SJakub Wojciech Klama "pack each val[i], for i in range(vdict[self.repeat])" 432*134e1779SJakub Wojciech Klama num = vdict[self.repeat] 433*134e1779SJakub Wojciech Klama assert num == len(val) 434*134e1779SJakub Wojciech Klama if self.sub is None: 435*134e1779SJakub Wojciech Klama assert isinstance(val, bytes) 436*134e1779SJakub Wojciech Klama return [val] 437*134e1779SJakub Wojciech Klama parts = [] 438*134e1779SJakub Wojciech Klama for i in val: 439*134e1779SJakub Wojciech Klama parts.extend(self.sub.apack(vdict, cdict, i)) 440*134e1779SJakub Wojciech Klama return parts 441*134e1779SJakub Wojciech Klama 442*134e1779SJakub Wojciech Klama def unpack(self, vdict, cdict, bstring, offset, noerror=False): 443*134e1779SJakub Wojciech Klama "unpack repeatedly, per self.repeat, into new array." 444*134e1779SJakub Wojciech Klama num = vdict[self.repeat] 445*134e1779SJakub Wojciech Klama if num is None and noerror: 446*134e1779SJakub Wojciech Klama num = 0 447*134e1779SJakub Wojciech Klama else: 448*134e1779SJakub Wojciech Klama assert num >= 0 449*134e1779SJakub Wojciech Klama if self.sub is None: 450*134e1779SJakub Wojciech Klama nexto = offset + num 451*134e1779SJakub Wojciech Klama if len(bstring) < nexto and not noerror: 452*134e1779SJakub Wojciech Klama raise SequenceError('out of data ' 453*134e1779SJakub Wojciech Klama 'while unpacking {0!r}'.format(self.name)) 454*134e1779SJakub Wojciech Klama return bstring[offset:nexto], nexto 455*134e1779SJakub Wojciech Klama array = [] 456*134e1779SJakub Wojciech Klama for i in range(num): 457*134e1779SJakub Wojciech Klama obj, offset = self.sub.unpack(vdict, cdict, bstring, offset, 458*134e1779SJakub Wojciech Klama noerror) 459*134e1779SJakub Wojciech Klama array.append(obj) 460*134e1779SJakub Wojciech Klama return array, offset 461*134e1779SJakub Wojciech Klama 462*134e1779SJakub Wojciech Klamaclass SequenceError(Exception): 463*134e1779SJakub Wojciech Klama "sequence error: item too big, or ran out of data" 464*134e1779SJakub Wojciech Klama pass 465*134e1779SJakub Wojciech Klama 466*134e1779SJakub Wojciech Klamaclass Sequencer(object): 467*134e1779SJakub Wojciech Klama r""" 468*134e1779SJakub Wojciech Klama A sequencer is an object that packs (marshals) or unpacks 469*134e1779SJakub Wojciech Klama (unmarshals) a series of objects, according to their EncDec 470*134e1779SJakub Wojciech Klama instances. 471*134e1779SJakub Wojciech Klama 472*134e1779SJakub Wojciech Klama The objects themselves (and their values) come from, or 473*134e1779SJakub Wojciech Klama go into, a dictionary: <vdict>, the first argument to 474*134e1779SJakub Wojciech Klama pack/unpack. 475*134e1779SJakub Wojciech Klama 476*134e1779SJakub Wojciech Klama Some fields may be conditional. The conditions are in a 477*134e1779SJakub Wojciech Klama separate dictionary (the second or <cdict> argument). 478*134e1779SJakub Wojciech Klama 479*134e1779SJakub Wojciech Klama Some objects may be dictionaries or PFODs, e.g., they may 480*134e1779SJakub Wojciech Klama be a Plan9 qid or stat structure. These have their own 481*134e1779SJakub Wojciech Klama sub-encoding. 482*134e1779SJakub Wojciech Klama 483*134e1779SJakub Wojciech Klama As with each encoder, we have both an apack() function 484*134e1779SJakub Wojciech Klama (returns a list of parts) and a plain pack(). Users should 485*134e1779SJakub Wojciech Klama mostly stick with plain pack(). 486*134e1779SJakub Wojciech Klama 487*134e1779SJakub Wojciech Klama >>> s = Sequencer('monty') 488*134e1779SJakub Wojciech Klama >>> s 489*134e1779SJakub Wojciech Klama Sequencer('monty') 490*134e1779SJakub Wojciech Klama >>> e = EncDecSimple('eggs', 2) 491*134e1779SJakub Wojciech Klama >>> s.append_encdec(None, e) 492*134e1779SJakub Wojciech Klama >>> s.append_encdec(None, EncDecSimple('spam', 1)) 493*134e1779SJakub Wojciech Klama >>> s[0] 494*134e1779SJakub Wojciech Klama (None, EncDecSimple('eggs', 2)) 495*134e1779SJakub Wojciech Klama >>> e.b2s(s.pack({'eggs': 513, 'spam': 65}, {})) 496*134e1779SJakub Wojciech Klama '\x01\x02A' 497*134e1779SJakub Wojciech Klama 498*134e1779SJakub Wojciech Klama When particular fields are conditional, they appear in 499*134e1779SJakub Wojciech Klama packed output, or are taken from the byte-string during 500*134e1779SJakub Wojciech Klama unpacking, only if their condition is true. 501*134e1779SJakub Wojciech Klama 502*134e1779SJakub Wojciech Klama As with struct, use unpack_from to start at an arbitrary 503*134e1779SJakub Wojciech Klama offset and/or omit verification that the entire byte-string 504*134e1779SJakub Wojciech Klama is consumed. 505*134e1779SJakub Wojciech Klama 506*134e1779SJakub Wojciech Klama >>> s = Sequencer('python') 507*134e1779SJakub Wojciech Klama >>> s.append_encdec(None, e) 508*134e1779SJakub Wojciech Klama >>> s.append_encdec('.u', EncDecSimple('spam', 1)) 509*134e1779SJakub Wojciech Klama >>> s[1] 510*134e1779SJakub Wojciech Klama ('.u', EncDecSimple('spam', 1)) 511*134e1779SJakub Wojciech Klama >>> e.b2s(s.pack({'eggs': 513, 'spam': 65}, {'.u': True})) 512*134e1779SJakub Wojciech Klama '\x01\x02A' 513*134e1779SJakub Wojciech Klama >>> e.b2s(s.pack({'eggs': 513, 'spam': 65}, {'.u': False})) 514*134e1779SJakub Wojciech Klama '\x01\x02' 515*134e1779SJakub Wojciech Klama 516*134e1779SJakub Wojciech Klama >>> d = {} 517*134e1779SJakub Wojciech Klama >>> s.unpack(d, {'.u': True}, b'\x01\x02A') 518*134e1779SJakub Wojciech Klama >>> print(d['eggs'], d['spam']) 519*134e1779SJakub Wojciech Klama 513 65 520*134e1779SJakub Wojciech Klama >>> d = {} 521*134e1779SJakub Wojciech Klama >>> s.unpack(d, {'.u': False}, b'\x01\x02A', 0) 522*134e1779SJakub Wojciech Klama Traceback (most recent call last): 523*134e1779SJakub Wojciech Klama ... 524*134e1779SJakub Wojciech Klama SequenceError: 1 byte(s) unconsumed 525*134e1779SJakub Wojciech Klama >>> s.unpack_from(d, {'.u': False}, b'\x01\x02A', 0) 526*134e1779SJakub Wojciech Klama 2 527*134e1779SJakub Wojciech Klama >>> print(d) 528*134e1779SJakub Wojciech Klama {'eggs': 513} 529*134e1779SJakub Wojciech Klama 530*134e1779SJakub Wojciech Klama The incoming dictionary-like object may be pre-initialized 531*134e1779SJakub Wojciech Klama if you like; only sequences that decode are filled-in: 532*134e1779SJakub Wojciech Klama 533*134e1779SJakub Wojciech Klama >>> d = {'eggs': None, 'spam': None} 534*134e1779SJakub Wojciech Klama >>> s.unpack_from(d, {'.u': False}, b'\x01\x02A', 0) 535*134e1779SJakub Wojciech Klama 2 536*134e1779SJakub Wojciech Klama >>> print(d['eggs'], d['spam']) 537*134e1779SJakub Wojciech Klama 513 None 538*134e1779SJakub Wojciech Klama 539*134e1779SJakub Wojciech Klama Some objects may be arrays; if so their EncDec is actually 540*134e1779SJakub Wojciech Klama an EncDecA, the repeat count must be in the dictionary, and 541*134e1779SJakub Wojciech Klama the object itself must have a len() and be index-able: 542*134e1779SJakub Wojciech Klama 543*134e1779SJakub Wojciech Klama >>> s = Sequencer('arr') 544*134e1779SJakub Wojciech Klama >>> s.append_encdec(None, EncDecSimple('n', 1)) 545*134e1779SJakub Wojciech Klama >>> ae = EncDecSimple('array', 2) 546*134e1779SJakub Wojciech Klama >>> s.append_encdec(None, EncDecA('n', 'array', ae)) 547*134e1779SJakub Wojciech Klama >>> ae.b2s(s.pack({'n': 2, 'array': [257, 514]}, {})) 548*134e1779SJakub Wojciech Klama '\x02\x01\x01\x02\x02' 549*134e1779SJakub Wojciech Klama 550*134e1779SJakub Wojciech Klama Unpacking an array creates a list of the number of items. 551*134e1779SJakub Wojciech Klama The EncDec encoder that decodes the number of items needs to 552*134e1779SJakub Wojciech Klama occur first in the sequencer, so that the dictionary will have 553*134e1779SJakub Wojciech Klama acquired the repeat-count variable's value by the time we hit 554*134e1779SJakub Wojciech Klama the array's encdec: 555*134e1779SJakub Wojciech Klama 556*134e1779SJakub Wojciech Klama >>> d = {} 557*134e1779SJakub Wojciech Klama >>> s.unpack(d, {}, b'\x01\x04\x00') 558*134e1779SJakub Wojciech Klama >>> d['n'], d['array'] 559*134e1779SJakub Wojciech Klama (1, [4]) 560*134e1779SJakub Wojciech Klama """ 561*134e1779SJakub Wojciech Klama def __init__(self, name): 562*134e1779SJakub Wojciech Klama self.name = name 563*134e1779SJakub Wojciech Klama self._codes = [] 564*134e1779SJakub Wojciech Klama self.debug = False # or sys.stderr 565*134e1779SJakub Wojciech Klama 566*134e1779SJakub Wojciech Klama def __repr__(self): 567*134e1779SJakub Wojciech Klama return '{0}({1!r})'.format(self.__class__.__name__, self.name) 568*134e1779SJakub Wojciech Klama 569*134e1779SJakub Wojciech Klama __str__ = __repr__ 570*134e1779SJakub Wojciech Klama 571*134e1779SJakub Wojciech Klama def __len__(self): 572*134e1779SJakub Wojciech Klama return len(self._codes) 573*134e1779SJakub Wojciech Klama 574*134e1779SJakub Wojciech Klama def __iter__(self): 575*134e1779SJakub Wojciech Klama return iter(self._codes) 576*134e1779SJakub Wojciech Klama 577*134e1779SJakub Wojciech Klama def __getitem__(self, index): 578*134e1779SJakub Wojciech Klama return self._codes[index] 579*134e1779SJakub Wojciech Klama 580*134e1779SJakub Wojciech Klama def dprint(self, *args, **kwargs): 581*134e1779SJakub Wojciech Klama if not self.debug: 582*134e1779SJakub Wojciech Klama return 583*134e1779SJakub Wojciech Klama if isinstance(self.debug, bool): 584*134e1779SJakub Wojciech Klama dest = sys.stdout 585*134e1779SJakub Wojciech Klama else: 586*134e1779SJakub Wojciech Klama dest = self.debug 587*134e1779SJakub Wojciech Klama print(*args, file=dest, **kwargs) 588*134e1779SJakub Wojciech Klama 589*134e1779SJakub Wojciech Klama def append_encdec(self, cond, code): 590*134e1779SJakub Wojciech Klama "add EncDec en/de-coder, conditional on cond" 591*134e1779SJakub Wojciech Klama self._codes.append((cond, code)) 592*134e1779SJakub Wojciech Klama 593*134e1779SJakub Wojciech Klama def apack(self, vdict, cdict): 594*134e1779SJakub Wojciech Klama """ 595*134e1779SJakub Wojciech Klama Produce packed representation of each field. 596*134e1779SJakub Wojciech Klama """ 597*134e1779SJakub Wojciech Klama packed_data = [] 598*134e1779SJakub Wojciech Klama for cond, code in self._codes: 599*134e1779SJakub Wojciech Klama # Skip this item if it's conditional on a false thing. 600*134e1779SJakub Wojciech Klama if cond is not None and not cdict[cond]: 601*134e1779SJakub Wojciech Klama self.dprint('skip %r - %r is False' % (code, cond)) 602*134e1779SJakub Wojciech Klama continue 603*134e1779SJakub Wojciech Klama 604*134e1779SJakub Wojciech Klama # Pack the item. 605*134e1779SJakub Wojciech Klama self.dprint('pack %r - no cond or %r is True' % (code, cond)) 606*134e1779SJakub Wojciech Klama packed_data.extend(code.apack(vdict, cdict, vdict[code.name])) 607*134e1779SJakub Wojciech Klama 608*134e1779SJakub Wojciech Klama return packed_data 609*134e1779SJakub Wojciech Klama 610*134e1779SJakub Wojciech Klama def pack(self, vdict, cdict): 611*134e1779SJakub Wojciech Klama """ 612*134e1779SJakub Wojciech Klama Flatten packed data. 613*134e1779SJakub Wojciech Klama """ 614*134e1779SJakub Wojciech Klama return b''.join(self.apack(vdict, cdict)) 615*134e1779SJakub Wojciech Klama 616*134e1779SJakub Wojciech Klama def unpack_from(self, vdict, cdict, bstring, offset=0, noerror=False): 617*134e1779SJakub Wojciech Klama """ 618*134e1779SJakub Wojciech Klama Unpack from byte string. 619*134e1779SJakub Wojciech Klama 620*134e1779SJakub Wojciech Klama The values are unpacked into a dictionary vdict; 621*134e1779SJakub Wojciech Klama some of its entries may themselves be ordered 622*134e1779SJakub Wojciech Klama dictionaries created by typedefed codes. 623*134e1779SJakub Wojciech Klama 624*134e1779SJakub Wojciech Klama Raises SequenceError if the string is too short, 625*134e1779SJakub Wojciech Klama unless you set noerror, in which case we assume 626*134e1779SJakub Wojciech Klama you want see what you can get out of the data. 627*134e1779SJakub Wojciech Klama """ 628*134e1779SJakub Wojciech Klama for cond, code in self._codes: 629*134e1779SJakub Wojciech Klama # Skip this item if it's conditional on a false thing. 630*134e1779SJakub Wojciech Klama if cond is not None and not cdict[cond]: 631*134e1779SJakub Wojciech Klama self.dprint('skip %r - %r is False' % (code, cond)) 632*134e1779SJakub Wojciech Klama continue 633*134e1779SJakub Wojciech Klama 634*134e1779SJakub Wojciech Klama # Unpack the item. 635*134e1779SJakub Wojciech Klama self.dprint('unpack %r - no cond or %r is True' % (code, cond)) 636*134e1779SJakub Wojciech Klama obj, offset = code.unpack(vdict, cdict, bstring, offset, noerror) 637*134e1779SJakub Wojciech Klama vdict[code.name] = obj 638*134e1779SJakub Wojciech Klama 639*134e1779SJakub Wojciech Klama return offset 640*134e1779SJakub Wojciech Klama 641*134e1779SJakub Wojciech Klama def unpack(self, vdict, cdict, bstring, noerror=False): 642*134e1779SJakub Wojciech Klama """ 643*134e1779SJakub Wojciech Klama Like unpack_from but unless noerror=True, requires that 644*134e1779SJakub Wojciech Klama we completely use up the given byte string. 645*134e1779SJakub Wojciech Klama """ 646*134e1779SJakub Wojciech Klama offset = self.unpack_from(vdict, cdict, bstring, 0, noerror) 647*134e1779SJakub Wojciech Klama if not noerror and offset != len(bstring): 648*134e1779SJakub Wojciech Klama raise SequenceError('{0} byte(s) unconsumed'.format( 649*134e1779SJakub Wojciech Klama len(bstring) - offset)) 650*134e1779SJakub Wojciech Klama 651*134e1779SJakub Wojciech Klamaif __name__ == '__main__': 652*134e1779SJakub Wojciech Klama import doctest 653*134e1779SJakub Wojciech Klama doctest.testmod() 654