14adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao"""Implements (a subset of) Sun XDR -- eXternal Data Representation.
24adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
34adfde8bc82dd39f59e0445588c3e599ada477dJosh GaoSee: RFC 1014
44adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
54adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao"""
64adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
74adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoimport struct
84adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaotry:
94adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    from cStringIO import StringIO as _StringIO
104adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoexcept ImportError:
114adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    from StringIO import StringIO as _StringIO
124adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
134adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao__all__ = ["Error", "Packer", "Unpacker", "ConversionError"]
144adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
154adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# exceptions
164adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass Error(Exception):
174adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    """Exception class for this module. Use:
184adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
194adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    except xdrlib.Error, var:
204adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # var has the Error instance for the exception
214adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
224adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    Public ivars:
234adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        msg -- contains the message
244adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
254adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    """
264adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __init__(self, msg):
274adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.msg = msg
284adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __repr__(self):
294adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return repr(self.msg)
304adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __str__(self):
314adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return str(self.msg)
324adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
334adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
344adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass ConversionError(Error):
354adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    pass
364adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
374adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
384adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
394adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass Packer:
404adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    """Pack various data representations into a buffer."""
414adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
424adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __init__(self):
434adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.reset()
444adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
454adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def reset(self):
464adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.__buf = _StringIO()
474adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
484adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def get_buffer(self):
494adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return self.__buf.getvalue()
504adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    # backwards compatibility
514adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    get_buf = get_buffer
524adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
534adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def pack_uint(self, x):
544adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.__buf.write(struct.pack('>L', x))
554adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
564adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def pack_int(self, x):
574adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.__buf.write(struct.pack('>l', x))
584adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
594adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    pack_enum = pack_int
604adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
614adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def pack_bool(self, x):
624adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if x: self.__buf.write('\0\0\0\1')
634adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        else: self.__buf.write('\0\0\0\0')
644adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
654adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def pack_uhyper(self, x):
664adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.pack_uint(x>>32 & 0xffffffffL)
674adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.pack_uint(x & 0xffffffffL)
684adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
694adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    pack_hyper = pack_uhyper
704adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
714adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def pack_float(self, x):
724adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        try: self.__buf.write(struct.pack('>f', x))
734adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        except struct.error, msg:
744adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            raise ConversionError, msg
754adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
764adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def pack_double(self, x):
774adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        try: self.__buf.write(struct.pack('>d', x))
784adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        except struct.error, msg:
794adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            raise ConversionError, msg
804adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
814adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def pack_fstring(self, n, s):
824adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if n < 0:
834adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            raise ValueError, 'fstring size must be nonnegative'
844adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        data = s[:n]
854adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        n = ((n+3)//4)*4
864adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        data = data + (n - len(data)) * '\0'
874adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.__buf.write(data)
884adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
894adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    pack_fopaque = pack_fstring
904adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
914adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def pack_string(self, s):
924adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        n = len(s)
934adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.pack_uint(n)
944adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.pack_fstring(n, s)
954adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
964adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    pack_opaque = pack_string
974adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    pack_bytes = pack_string
984adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
994adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def pack_list(self, list, pack_item):
1004adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        for item in list:
1014adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            self.pack_uint(1)
1024adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            pack_item(item)
1034adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.pack_uint(0)
1044adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1054adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def pack_farray(self, n, list, pack_item):
1064adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if len(list) != n:
1074adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            raise ValueError, 'wrong array size'
1084adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        for item in list:
1094adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            pack_item(item)
1104adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1114adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def pack_array(self, list, pack_item):
1124adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        n = len(list)
1134adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.pack_uint(n)
1144adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.pack_farray(n, list, pack_item)
1154adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1164adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1174adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1184adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass Unpacker:
1194adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    """Unpacks various data representations from the given buffer."""
1204adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1214adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __init__(self, data):
1224adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.reset(data)
1234adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1244adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def reset(self, data):
1254adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.__buf = data
1264adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.__pos = 0
1274adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1284adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def get_position(self):
1294adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return self.__pos
1304adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1314adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def set_position(self, position):
1324adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.__pos = position
1334adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1344adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def get_buffer(self):
1354adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return self.__buf
1364adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1374adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def done(self):
1384adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if self.__pos < len(self.__buf):
1394adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            raise Error('unextracted data remains')
1404adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1414adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def unpack_uint(self):
1424adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        i = self.__pos
1434adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.__pos = j = i+4
1444adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        data = self.__buf[i:j]
1454adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if len(data) < 4:
1464adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            raise EOFError
1474adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        x = struct.unpack('>L', data)[0]
1484adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        try:
1494adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            return int(x)
1504adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        except OverflowError:
1514adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            return x
1524adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1534adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def unpack_int(self):
1544adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        i = self.__pos
1554adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.__pos = j = i+4
1564adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        data = self.__buf[i:j]
1574adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if len(data) < 4:
1584adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            raise EOFError
1594adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return struct.unpack('>l', data)[0]
1604adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1614adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    unpack_enum = unpack_int
1624adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1634adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def unpack_bool(self):
1644adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return bool(self.unpack_int())
1654adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1664adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def unpack_uhyper(self):
1674adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        hi = self.unpack_uint()
1684adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        lo = self.unpack_uint()
1694adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return long(hi)<<32 | lo
1704adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1714adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def unpack_hyper(self):
1724adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        x = self.unpack_uhyper()
1734adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if x >= 0x8000000000000000L:
1744adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            x = x - 0x10000000000000000L
1754adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return x
1764adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1774adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def unpack_float(self):
1784adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        i = self.__pos
1794adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.__pos = j = i+4
1804adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        data = self.__buf[i:j]
1814adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if len(data) < 4:
1824adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            raise EOFError
1834adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return struct.unpack('>f', data)[0]
1844adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1854adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def unpack_double(self):
1864adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        i = self.__pos
1874adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.__pos = j = i+8
1884adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        data = self.__buf[i:j]
1894adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if len(data) < 8:
1904adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            raise EOFError
1914adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return struct.unpack('>d', data)[0]
1924adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1934adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def unpack_fstring(self, n):
1944adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if n < 0:
1954adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            raise ValueError, 'fstring size must be nonnegative'
1964adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        i = self.__pos
1974adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        j = i + (n+3)//4*4
1984adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if j > len(self.__buf):
1994adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            raise EOFError
2004adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.__pos = j
2014adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return self.__buf[i:i+n]
2024adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2034adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    unpack_fopaque = unpack_fstring
2044adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2054adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def unpack_string(self):
2064adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        n = self.unpack_uint()
2074adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return self.unpack_fstring(n)
2084adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2094adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    unpack_opaque = unpack_string
2104adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    unpack_bytes = unpack_string
2114adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2124adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def unpack_list(self, unpack_item):
2134adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        list = []
2144adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        while 1:
2154adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            x = self.unpack_uint()
2164adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            if x == 0: break
2174adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            if x != 1:
2184adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                raise ConversionError, '0 or 1 expected, got %r' % (x,)
2194adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            item = unpack_item()
2204adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            list.append(item)
2214adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return list
2224adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2234adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def unpack_farray(self, n, unpack_item):
2244adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        list = []
2254adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        for i in range(n):
2264adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            list.append(unpack_item())
2274adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return list
2284adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2294adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def unpack_array(self, unpack_item):
2304adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        n = self.unpack_uint()
2314adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return self.unpack_farray(n, unpack_item)
232