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