1*cda5da8dSAndroid Build Coastguard Worker"""Implements (a subset of) Sun XDR -- eXternal Data Representation. 2*cda5da8dSAndroid Build Coastguard Worker 3*cda5da8dSAndroid Build Coastguard WorkerSee: RFC 1014 4*cda5da8dSAndroid Build Coastguard Worker 5*cda5da8dSAndroid Build Coastguard Worker""" 6*cda5da8dSAndroid Build Coastguard Worker 7*cda5da8dSAndroid Build Coastguard Workerimport struct 8*cda5da8dSAndroid Build Coastguard Workerfrom io import BytesIO 9*cda5da8dSAndroid Build Coastguard Workerfrom functools import wraps 10*cda5da8dSAndroid Build Coastguard Workerimport warnings 11*cda5da8dSAndroid Build Coastguard Worker 12*cda5da8dSAndroid Build Coastguard Workerwarnings._deprecated(__name__, remove=(3, 13)) 13*cda5da8dSAndroid Build Coastguard Worker 14*cda5da8dSAndroid Build Coastguard Worker__all__ = ["Error", "Packer", "Unpacker", "ConversionError"] 15*cda5da8dSAndroid Build Coastguard Worker 16*cda5da8dSAndroid Build Coastguard Worker# exceptions 17*cda5da8dSAndroid Build Coastguard Workerclass Error(Exception): 18*cda5da8dSAndroid Build Coastguard Worker """Exception class for this module. Use: 19*cda5da8dSAndroid Build Coastguard Worker 20*cda5da8dSAndroid Build Coastguard Worker except xdrlib.Error as var: 21*cda5da8dSAndroid Build Coastguard Worker # var has the Error instance for the exception 22*cda5da8dSAndroid Build Coastguard Worker 23*cda5da8dSAndroid Build Coastguard Worker Public ivars: 24*cda5da8dSAndroid Build Coastguard Worker msg -- contains the message 25*cda5da8dSAndroid Build Coastguard Worker 26*cda5da8dSAndroid Build Coastguard Worker """ 27*cda5da8dSAndroid Build Coastguard Worker def __init__(self, msg): 28*cda5da8dSAndroid Build Coastguard Worker self.msg = msg 29*cda5da8dSAndroid Build Coastguard Worker def __repr__(self): 30*cda5da8dSAndroid Build Coastguard Worker return repr(self.msg) 31*cda5da8dSAndroid Build Coastguard Worker def __str__(self): 32*cda5da8dSAndroid Build Coastguard Worker return str(self.msg) 33*cda5da8dSAndroid Build Coastguard Worker 34*cda5da8dSAndroid Build Coastguard Worker 35*cda5da8dSAndroid Build Coastguard Workerclass ConversionError(Error): 36*cda5da8dSAndroid Build Coastguard Worker pass 37*cda5da8dSAndroid Build Coastguard Worker 38*cda5da8dSAndroid Build Coastguard Workerdef raise_conversion_error(function): 39*cda5da8dSAndroid Build Coastguard Worker """ Wrap any raised struct.errors in a ConversionError. """ 40*cda5da8dSAndroid Build Coastguard Worker 41*cda5da8dSAndroid Build Coastguard Worker @wraps(function) 42*cda5da8dSAndroid Build Coastguard Worker def result(self, value): 43*cda5da8dSAndroid Build Coastguard Worker try: 44*cda5da8dSAndroid Build Coastguard Worker return function(self, value) 45*cda5da8dSAndroid Build Coastguard Worker except struct.error as e: 46*cda5da8dSAndroid Build Coastguard Worker raise ConversionError(e.args[0]) from None 47*cda5da8dSAndroid Build Coastguard Worker return result 48*cda5da8dSAndroid Build Coastguard Worker 49*cda5da8dSAndroid Build Coastguard Worker 50*cda5da8dSAndroid Build Coastguard Workerclass Packer: 51*cda5da8dSAndroid Build Coastguard Worker """Pack various data representations into a buffer.""" 52*cda5da8dSAndroid Build Coastguard Worker 53*cda5da8dSAndroid Build Coastguard Worker def __init__(self): 54*cda5da8dSAndroid Build Coastguard Worker self.reset() 55*cda5da8dSAndroid Build Coastguard Worker 56*cda5da8dSAndroid Build Coastguard Worker def reset(self): 57*cda5da8dSAndroid Build Coastguard Worker self.__buf = BytesIO() 58*cda5da8dSAndroid Build Coastguard Worker 59*cda5da8dSAndroid Build Coastguard Worker def get_buffer(self): 60*cda5da8dSAndroid Build Coastguard Worker return self.__buf.getvalue() 61*cda5da8dSAndroid Build Coastguard Worker # backwards compatibility 62*cda5da8dSAndroid Build Coastguard Worker get_buf = get_buffer 63*cda5da8dSAndroid Build Coastguard Worker 64*cda5da8dSAndroid Build Coastguard Worker @raise_conversion_error 65*cda5da8dSAndroid Build Coastguard Worker def pack_uint(self, x): 66*cda5da8dSAndroid Build Coastguard Worker self.__buf.write(struct.pack('>L', x)) 67*cda5da8dSAndroid Build Coastguard Worker 68*cda5da8dSAndroid Build Coastguard Worker @raise_conversion_error 69*cda5da8dSAndroid Build Coastguard Worker def pack_int(self, x): 70*cda5da8dSAndroid Build Coastguard Worker self.__buf.write(struct.pack('>l', x)) 71*cda5da8dSAndroid Build Coastguard Worker 72*cda5da8dSAndroid Build Coastguard Worker pack_enum = pack_int 73*cda5da8dSAndroid Build Coastguard Worker 74*cda5da8dSAndroid Build Coastguard Worker def pack_bool(self, x): 75*cda5da8dSAndroid Build Coastguard Worker if x: self.__buf.write(b'\0\0\0\1') 76*cda5da8dSAndroid Build Coastguard Worker else: self.__buf.write(b'\0\0\0\0') 77*cda5da8dSAndroid Build Coastguard Worker 78*cda5da8dSAndroid Build Coastguard Worker def pack_uhyper(self, x): 79*cda5da8dSAndroid Build Coastguard Worker try: 80*cda5da8dSAndroid Build Coastguard Worker self.pack_uint(x>>32 & 0xffffffff) 81*cda5da8dSAndroid Build Coastguard Worker except (TypeError, struct.error) as e: 82*cda5da8dSAndroid Build Coastguard Worker raise ConversionError(e.args[0]) from None 83*cda5da8dSAndroid Build Coastguard Worker try: 84*cda5da8dSAndroid Build Coastguard Worker self.pack_uint(x & 0xffffffff) 85*cda5da8dSAndroid Build Coastguard Worker except (TypeError, struct.error) as e: 86*cda5da8dSAndroid Build Coastguard Worker raise ConversionError(e.args[0]) from None 87*cda5da8dSAndroid Build Coastguard Worker 88*cda5da8dSAndroid Build Coastguard Worker pack_hyper = pack_uhyper 89*cda5da8dSAndroid Build Coastguard Worker 90*cda5da8dSAndroid Build Coastguard Worker @raise_conversion_error 91*cda5da8dSAndroid Build Coastguard Worker def pack_float(self, x): 92*cda5da8dSAndroid Build Coastguard Worker self.__buf.write(struct.pack('>f', x)) 93*cda5da8dSAndroid Build Coastguard Worker 94*cda5da8dSAndroid Build Coastguard Worker @raise_conversion_error 95*cda5da8dSAndroid Build Coastguard Worker def pack_double(self, x): 96*cda5da8dSAndroid Build Coastguard Worker self.__buf.write(struct.pack('>d', x)) 97*cda5da8dSAndroid Build Coastguard Worker 98*cda5da8dSAndroid Build Coastguard Worker def pack_fstring(self, n, s): 99*cda5da8dSAndroid Build Coastguard Worker if n < 0: 100*cda5da8dSAndroid Build Coastguard Worker raise ValueError('fstring size must be nonnegative') 101*cda5da8dSAndroid Build Coastguard Worker data = s[:n] 102*cda5da8dSAndroid Build Coastguard Worker n = ((n+3)//4)*4 103*cda5da8dSAndroid Build Coastguard Worker data = data + (n - len(data)) * b'\0' 104*cda5da8dSAndroid Build Coastguard Worker self.__buf.write(data) 105*cda5da8dSAndroid Build Coastguard Worker 106*cda5da8dSAndroid Build Coastguard Worker pack_fopaque = pack_fstring 107*cda5da8dSAndroid Build Coastguard Worker 108*cda5da8dSAndroid Build Coastguard Worker def pack_string(self, s): 109*cda5da8dSAndroid Build Coastguard Worker n = len(s) 110*cda5da8dSAndroid Build Coastguard Worker self.pack_uint(n) 111*cda5da8dSAndroid Build Coastguard Worker self.pack_fstring(n, s) 112*cda5da8dSAndroid Build Coastguard Worker 113*cda5da8dSAndroid Build Coastguard Worker pack_opaque = pack_string 114*cda5da8dSAndroid Build Coastguard Worker pack_bytes = pack_string 115*cda5da8dSAndroid Build Coastguard Worker 116*cda5da8dSAndroid Build Coastguard Worker def pack_list(self, list, pack_item): 117*cda5da8dSAndroid Build Coastguard Worker for item in list: 118*cda5da8dSAndroid Build Coastguard Worker self.pack_uint(1) 119*cda5da8dSAndroid Build Coastguard Worker pack_item(item) 120*cda5da8dSAndroid Build Coastguard Worker self.pack_uint(0) 121*cda5da8dSAndroid Build Coastguard Worker 122*cda5da8dSAndroid Build Coastguard Worker def pack_farray(self, n, list, pack_item): 123*cda5da8dSAndroid Build Coastguard Worker if len(list) != n: 124*cda5da8dSAndroid Build Coastguard Worker raise ValueError('wrong array size') 125*cda5da8dSAndroid Build Coastguard Worker for item in list: 126*cda5da8dSAndroid Build Coastguard Worker pack_item(item) 127*cda5da8dSAndroid Build Coastguard Worker 128*cda5da8dSAndroid Build Coastguard Worker def pack_array(self, list, pack_item): 129*cda5da8dSAndroid Build Coastguard Worker n = len(list) 130*cda5da8dSAndroid Build Coastguard Worker self.pack_uint(n) 131*cda5da8dSAndroid Build Coastguard Worker self.pack_farray(n, list, pack_item) 132*cda5da8dSAndroid Build Coastguard Worker 133*cda5da8dSAndroid Build Coastguard Worker 134*cda5da8dSAndroid Build Coastguard Worker 135*cda5da8dSAndroid Build Coastguard Workerclass Unpacker: 136*cda5da8dSAndroid Build Coastguard Worker """Unpacks various data representations from the given buffer.""" 137*cda5da8dSAndroid Build Coastguard Worker 138*cda5da8dSAndroid Build Coastguard Worker def __init__(self, data): 139*cda5da8dSAndroid Build Coastguard Worker self.reset(data) 140*cda5da8dSAndroid Build Coastguard Worker 141*cda5da8dSAndroid Build Coastguard Worker def reset(self, data): 142*cda5da8dSAndroid Build Coastguard Worker self.__buf = data 143*cda5da8dSAndroid Build Coastguard Worker self.__pos = 0 144*cda5da8dSAndroid Build Coastguard Worker 145*cda5da8dSAndroid Build Coastguard Worker def get_position(self): 146*cda5da8dSAndroid Build Coastguard Worker return self.__pos 147*cda5da8dSAndroid Build Coastguard Worker 148*cda5da8dSAndroid Build Coastguard Worker def set_position(self, position): 149*cda5da8dSAndroid Build Coastguard Worker self.__pos = position 150*cda5da8dSAndroid Build Coastguard Worker 151*cda5da8dSAndroid Build Coastguard Worker def get_buffer(self): 152*cda5da8dSAndroid Build Coastguard Worker return self.__buf 153*cda5da8dSAndroid Build Coastguard Worker 154*cda5da8dSAndroid Build Coastguard Worker def done(self): 155*cda5da8dSAndroid Build Coastguard Worker if self.__pos < len(self.__buf): 156*cda5da8dSAndroid Build Coastguard Worker raise Error('unextracted data remains') 157*cda5da8dSAndroid Build Coastguard Worker 158*cda5da8dSAndroid Build Coastguard Worker def unpack_uint(self): 159*cda5da8dSAndroid Build Coastguard Worker i = self.__pos 160*cda5da8dSAndroid Build Coastguard Worker self.__pos = j = i+4 161*cda5da8dSAndroid Build Coastguard Worker data = self.__buf[i:j] 162*cda5da8dSAndroid Build Coastguard Worker if len(data) < 4: 163*cda5da8dSAndroid Build Coastguard Worker raise EOFError 164*cda5da8dSAndroid Build Coastguard Worker return struct.unpack('>L', data)[0] 165*cda5da8dSAndroid Build Coastguard Worker 166*cda5da8dSAndroid Build Coastguard Worker def unpack_int(self): 167*cda5da8dSAndroid Build Coastguard Worker i = self.__pos 168*cda5da8dSAndroid Build Coastguard Worker self.__pos = j = i+4 169*cda5da8dSAndroid Build Coastguard Worker data = self.__buf[i:j] 170*cda5da8dSAndroid Build Coastguard Worker if len(data) < 4: 171*cda5da8dSAndroid Build Coastguard Worker raise EOFError 172*cda5da8dSAndroid Build Coastguard Worker return struct.unpack('>l', data)[0] 173*cda5da8dSAndroid Build Coastguard Worker 174*cda5da8dSAndroid Build Coastguard Worker unpack_enum = unpack_int 175*cda5da8dSAndroid Build Coastguard Worker 176*cda5da8dSAndroid Build Coastguard Worker def unpack_bool(self): 177*cda5da8dSAndroid Build Coastguard Worker return bool(self.unpack_int()) 178*cda5da8dSAndroid Build Coastguard Worker 179*cda5da8dSAndroid Build Coastguard Worker def unpack_uhyper(self): 180*cda5da8dSAndroid Build Coastguard Worker hi = self.unpack_uint() 181*cda5da8dSAndroid Build Coastguard Worker lo = self.unpack_uint() 182*cda5da8dSAndroid Build Coastguard Worker return int(hi)<<32 | lo 183*cda5da8dSAndroid Build Coastguard Worker 184*cda5da8dSAndroid Build Coastguard Worker def unpack_hyper(self): 185*cda5da8dSAndroid Build Coastguard Worker x = self.unpack_uhyper() 186*cda5da8dSAndroid Build Coastguard Worker if x >= 0x8000000000000000: 187*cda5da8dSAndroid Build Coastguard Worker x = x - 0x10000000000000000 188*cda5da8dSAndroid Build Coastguard Worker return x 189*cda5da8dSAndroid Build Coastguard Worker 190*cda5da8dSAndroid Build Coastguard Worker def unpack_float(self): 191*cda5da8dSAndroid Build Coastguard Worker i = self.__pos 192*cda5da8dSAndroid Build Coastguard Worker self.__pos = j = i+4 193*cda5da8dSAndroid Build Coastguard Worker data = self.__buf[i:j] 194*cda5da8dSAndroid Build Coastguard Worker if len(data) < 4: 195*cda5da8dSAndroid Build Coastguard Worker raise EOFError 196*cda5da8dSAndroid Build Coastguard Worker return struct.unpack('>f', data)[0] 197*cda5da8dSAndroid Build Coastguard Worker 198*cda5da8dSAndroid Build Coastguard Worker def unpack_double(self): 199*cda5da8dSAndroid Build Coastguard Worker i = self.__pos 200*cda5da8dSAndroid Build Coastguard Worker self.__pos = j = i+8 201*cda5da8dSAndroid Build Coastguard Worker data = self.__buf[i:j] 202*cda5da8dSAndroid Build Coastguard Worker if len(data) < 8: 203*cda5da8dSAndroid Build Coastguard Worker raise EOFError 204*cda5da8dSAndroid Build Coastguard Worker return struct.unpack('>d', data)[0] 205*cda5da8dSAndroid Build Coastguard Worker 206*cda5da8dSAndroid Build Coastguard Worker def unpack_fstring(self, n): 207*cda5da8dSAndroid Build Coastguard Worker if n < 0: 208*cda5da8dSAndroid Build Coastguard Worker raise ValueError('fstring size must be nonnegative') 209*cda5da8dSAndroid Build Coastguard Worker i = self.__pos 210*cda5da8dSAndroid Build Coastguard Worker j = i + (n+3)//4*4 211*cda5da8dSAndroid Build Coastguard Worker if j > len(self.__buf): 212*cda5da8dSAndroid Build Coastguard Worker raise EOFError 213*cda5da8dSAndroid Build Coastguard Worker self.__pos = j 214*cda5da8dSAndroid Build Coastguard Worker return self.__buf[i:i+n] 215*cda5da8dSAndroid Build Coastguard Worker 216*cda5da8dSAndroid Build Coastguard Worker unpack_fopaque = unpack_fstring 217*cda5da8dSAndroid Build Coastguard Worker 218*cda5da8dSAndroid Build Coastguard Worker def unpack_string(self): 219*cda5da8dSAndroid Build Coastguard Worker n = self.unpack_uint() 220*cda5da8dSAndroid Build Coastguard Worker return self.unpack_fstring(n) 221*cda5da8dSAndroid Build Coastguard Worker 222*cda5da8dSAndroid Build Coastguard Worker unpack_opaque = unpack_string 223*cda5da8dSAndroid Build Coastguard Worker unpack_bytes = unpack_string 224*cda5da8dSAndroid Build Coastguard Worker 225*cda5da8dSAndroid Build Coastguard Worker def unpack_list(self, unpack_item): 226*cda5da8dSAndroid Build Coastguard Worker list = [] 227*cda5da8dSAndroid Build Coastguard Worker while 1: 228*cda5da8dSAndroid Build Coastguard Worker x = self.unpack_uint() 229*cda5da8dSAndroid Build Coastguard Worker if x == 0: break 230*cda5da8dSAndroid Build Coastguard Worker if x != 1: 231*cda5da8dSAndroid Build Coastguard Worker raise ConversionError('0 or 1 expected, got %r' % (x,)) 232*cda5da8dSAndroid Build Coastguard Worker item = unpack_item() 233*cda5da8dSAndroid Build Coastguard Worker list.append(item) 234*cda5da8dSAndroid Build Coastguard Worker return list 235*cda5da8dSAndroid Build Coastguard Worker 236*cda5da8dSAndroid Build Coastguard Worker def unpack_farray(self, n, unpack_item): 237*cda5da8dSAndroid Build Coastguard Worker list = [] 238*cda5da8dSAndroid Build Coastguard Worker for i in range(n): 239*cda5da8dSAndroid Build Coastguard Worker list.append(unpack_item()) 240*cda5da8dSAndroid Build Coastguard Worker return list 241*cda5da8dSAndroid Build Coastguard Worker 242*cda5da8dSAndroid Build Coastguard Worker def unpack_array(self, unpack_item): 243*cda5da8dSAndroid Build Coastguard Worker n = self.unpack_uint() 244*cda5da8dSAndroid Build Coastguard Worker return self.unpack_farray(n, unpack_item) 245