blob: 5d012e905b56fe5c6020cc82b364be2c66473d77 [file] [log] [blame]
Guido van Rossum731630b1996-08-19 22:26:43 +00001"""Implements (a subset of) Sun XDR -- eXternal Data Representation.
2
3See: RFC 1014
4
Guido van Rossum731630b1996-08-19 22:26:43 +00005"""
6
7import struct
Guido van Rossum731630b1996-08-19 22:26:43 +00008
Skip Montanaro40fc1602001-03-01 04:27:19 +00009__all__ = ["Error", "Packer", "Unpacker", "ConversionError"]
10
Guido van Rossum731630b1996-08-19 22:26:43 +000011# exceptions
12class Error:
13 """Exception class for this module. Use:
14
15 except xdrlib.Error, var:
16 # var has the Error instance for the exception
17
18 Public ivars:
19 msg -- contains the message
20
21 """
22 def __init__(self, msg):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000023 self.msg = msg
Guido van Rossum731630b1996-08-19 22:26:43 +000024 def __repr__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000025 return repr(self.msg)
Guido van Rossum731630b1996-08-19 22:26:43 +000026 def __str__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000027 return str(self.msg)
Guido van Rossum731630b1996-08-19 22:26:43 +000028
29
30class ConversionError(Error):
31 pass
32
33
Tim Peterse1190062001-01-15 03:34:38 +000034
Guido van Rossum731630b1996-08-19 22:26:43 +000035class Packer:
36 """Pack various data representations into a buffer."""
37
38 def __init__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000039 self.reset()
Guido van Rossum731630b1996-08-19 22:26:43 +000040
41 def reset(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000042 self.__buf = ''
Guido van Rossum731630b1996-08-19 22:26:43 +000043
44 def get_buffer(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000045 return self.__buf
Guido van Rossum731630b1996-08-19 22:26:43 +000046 # backwards compatibility
47 get_buf = get_buffer
48
49 def pack_uint(self, x):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000050 self.__buf = self.__buf + struct.pack('>L', x)
Guido van Rossum731630b1996-08-19 22:26:43 +000051
52 pack_int = pack_uint
53 pack_enum = pack_int
54
55 def pack_bool(self, x):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000056 if x: self.__buf = self.__buf + '\0\0\0\1'
57 else: self.__buf = self.__buf + '\0\0\0\0'
Guido van Rossum731630b1996-08-19 22:26:43 +000058
59 def pack_uhyper(self, x):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000060 self.pack_uint(x>>32 & 0xffffffffL)
61 self.pack_uint(x & 0xffffffffL)
Guido van Rossum731630b1996-08-19 22:26:43 +000062
63 pack_hyper = pack_uhyper
64
65 def pack_float(self, x):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000066 try: self.__buf = self.__buf + struct.pack('>f', x)
67 except struct.error, msg:
68 raise ConversionError, msg
Guido van Rossum6083f0e1997-01-02 22:52:15 +000069
Guido van Rossum731630b1996-08-19 22:26:43 +000070 def pack_double(self, x):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000071 try: self.__buf = self.__buf + struct.pack('>d', x)
72 except struct.error, msg:
73 raise ConversionError, msg
Guido van Rossum731630b1996-08-19 22:26:43 +000074
75 def pack_fstring(self, n, s):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000076 if n < 0:
77 raise ValueError, 'fstring size must be nonnegative'
78 n = ((n+3)/4)*4
79 data = s[:n]
80 data = data + (n - len(data)) * '\0'
81 self.__buf = self.__buf + data
Guido van Rossum731630b1996-08-19 22:26:43 +000082
83 pack_fopaque = pack_fstring
84
85 def pack_string(self, s):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000086 n = len(s)
87 self.pack_uint(n)
88 self.pack_fstring(n, s)
Guido van Rossum731630b1996-08-19 22:26:43 +000089
90 pack_opaque = pack_string
91 pack_bytes = pack_string
92
93 def pack_list(self, list, pack_item):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000094 for item in list:
95 self.pack_uint(1)
96 pack_item(item)
97 self.pack_uint(0)
Guido van Rossum731630b1996-08-19 22:26:43 +000098
99 def pack_farray(self, n, list, pack_item):
Fred Drake8152d322000-12-12 23:20:45 +0000100 if len(list) != n:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000101 raise ValueError, 'wrong array size'
102 for item in list:
103 pack_item(item)
Guido van Rossum731630b1996-08-19 22:26:43 +0000104
105 def pack_array(self, list, pack_item):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000106 n = len(list)
107 self.pack_uint(n)
108 self.pack_farray(n, list, pack_item)
Guido van Rossum731630b1996-08-19 22:26:43 +0000109
110
Tim Peterse1190062001-01-15 03:34:38 +0000111
Guido van Rossum731630b1996-08-19 22:26:43 +0000112class Unpacker:
113 """Unpacks various data representations from the given buffer."""
114
115 def __init__(self, data):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000116 self.reset(data)
Guido van Rossum731630b1996-08-19 22:26:43 +0000117
118 def reset(self, data):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000119 self.__buf = data
120 self.__pos = 0
Guido van Rossum731630b1996-08-19 22:26:43 +0000121
122 def get_position(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000123 return self.__pos
Guido van Rossum731630b1996-08-19 22:26:43 +0000124
125 def set_position(self, position):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000126 self.__pos = position
Guido van Rossum731630b1996-08-19 22:26:43 +0000127
Barry Warsaw75eccc51996-12-04 22:04:39 +0000128 def get_buffer(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000129 return self.__buf
Barry Warsaw75eccc51996-12-04 22:04:39 +0000130
Guido van Rossum731630b1996-08-19 22:26:43 +0000131 def done(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000132 if self.__pos < len(self.__buf):
133 raise Error('unextracted data remains')
Guido van Rossum731630b1996-08-19 22:26:43 +0000134
135 def unpack_uint(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000136 i = self.__pos
137 self.__pos = j = i+4
138 data = self.__buf[i:j]
139 if len(data) < 4:
140 raise EOFError
141 x = struct.unpack('>L', data)[0]
142 try:
143 return int(x)
144 except OverflowError:
145 return x
Guido van Rossum731630b1996-08-19 22:26:43 +0000146
147 def unpack_int(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000148 i = self.__pos
149 self.__pos = j = i+4
150 data = self.__buf[i:j]
151 if len(data) < 4:
152 raise EOFError
153 return struct.unpack('>l', data)[0]
Guido van Rossum731630b1996-08-19 22:26:43 +0000154
155 unpack_enum = unpack_int
156 unpack_bool = unpack_int
157
158 def unpack_uhyper(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000159 hi = self.unpack_uint()
160 lo = self.unpack_uint()
161 return long(hi)<<32 | lo
Guido van Rossum731630b1996-08-19 22:26:43 +0000162
163 def unpack_hyper(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000164 x = self.unpack_uhyper()
165 if x >= 0x8000000000000000L:
166 x = x - 0x10000000000000000L
167 return x
Guido van Rossum731630b1996-08-19 22:26:43 +0000168
169 def unpack_float(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000170 i = self.__pos
171 self.__pos = j = i+4
172 data = self.__buf[i:j]
173 if len(data) < 4:
174 raise EOFError
175 return struct.unpack('>f', data)[0]
Guido van Rossum731630b1996-08-19 22:26:43 +0000176
Guido van Rossum6083f0e1997-01-02 22:52:15 +0000177 def unpack_double(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000178 i = self.__pos
179 self.__pos = j = i+8
180 data = self.__buf[i:j]
181 if len(data) < 8:
182 raise EOFError
183 return struct.unpack('>d', data)[0]
Guido van Rossum731630b1996-08-19 22:26:43 +0000184
185 def unpack_fstring(self, n):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000186 if n < 0:
187 raise ValueError, 'fstring size must be nonnegative'
188 i = self.__pos
189 j = i + (n+3)/4*4
190 if j > len(self.__buf):
191 raise EOFError
192 self.__pos = j
193 return self.__buf[i:i+n]
Guido van Rossum731630b1996-08-19 22:26:43 +0000194
195 unpack_fopaque = unpack_fstring
196
197 def unpack_string(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000198 n = self.unpack_uint()
199 return self.unpack_fstring(n)
Guido van Rossum731630b1996-08-19 22:26:43 +0000200
201 unpack_opaque = unpack_string
202 unpack_bytes = unpack_string
203
204 def unpack_list(self, unpack_item):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000205 list = []
206 while 1:
207 x = self.unpack_uint()
208 if x == 0: break
Fred Drake8152d322000-12-12 23:20:45 +0000209 if x != 1:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000210 raise ConversionError, '0 or 1 expected, got ' + `x`
211 item = unpack_item()
212 list.append(item)
213 return list
Guido van Rossum731630b1996-08-19 22:26:43 +0000214
215 def unpack_farray(self, n, unpack_item):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000216 list = []
217 for i in range(n):
218 list.append(unpack_item())
219 return list
Guido van Rossum731630b1996-08-19 22:26:43 +0000220
221 def unpack_array(self, unpack_item):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000222 n = self.unpack_uint()
223 return self.unpack_farray(n, unpack_item)
Guido van Rossum731630b1996-08-19 22:26:43 +0000224
Tim Peterse1190062001-01-15 03:34:38 +0000225
Guido van Rossum731630b1996-08-19 22:26:43 +0000226# test suite
Guido van Rossum72fba791996-08-19 22:49:35 +0000227def _test():
Guido van Rossum731630b1996-08-19 22:26:43 +0000228 p = Packer()
229 packtest = [
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000230 (p.pack_uint, (9,)),
231 (p.pack_bool, (None,)),
232 (p.pack_bool, ('hello',)),
233 (p.pack_uhyper, (45L,)),
234 (p.pack_float, (1.9,)),
235 (p.pack_double, (1.9,)),
236 (p.pack_string, ('hello world',)),
237 (p.pack_list, (range(5), p.pack_uint)),
238 (p.pack_array, (['what', 'is', 'hapnin', 'doctor'], p.pack_string)),
239 ]
Guido van Rossum731630b1996-08-19 22:26:43 +0000240 succeedlist = [1] * len(packtest)
241 count = 0
242 for method, args in packtest:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000243 print 'pack test', count,
244 try:
245 apply(method, args)
246 print 'succeeded'
247 except ConversionError, var:
248 print 'ConversionError:', var.msg
249 succeedlist[count] = 0
250 count = count + 1
Guido van Rossum731630b1996-08-19 22:26:43 +0000251 data = p.get_buffer()
252 # now verify
253 up = Unpacker(data)
254 unpacktest = [
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000255 (up.unpack_uint, (), lambda x: x == 9),
256 (up.unpack_bool, (), lambda x: not x),
257 (up.unpack_bool, (), lambda x: x),
258 (up.unpack_uhyper, (), lambda x: x == 45L),
259 (up.unpack_float, (), lambda x: 1.89 < x < 1.91),
260 (up.unpack_double, (), lambda x: 1.89 < x < 1.91),
261 (up.unpack_string, (), lambda x: x == 'hello world'),
262 (up.unpack_list, (up.unpack_uint,), lambda x: x == range(5)),
263 (up.unpack_array, (up.unpack_string,),
264 lambda x: x == ['what', 'is', 'hapnin', 'doctor']),
265 ]
Guido van Rossum731630b1996-08-19 22:26:43 +0000266 count = 0
267 for method, args, pred in unpacktest:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000268 print 'unpack test', count,
269 try:
270 if succeedlist[count]:
271 x = apply(method, args)
272 print pred(x) and 'succeeded' or 'failed', ':', x
273 else:
274 print 'skipping'
275 except ConversionError, var:
276 print 'ConversionError:', var.msg
277 count = count + 1
Guido van Rossum731630b1996-08-19 22:26:43 +0000278
Tim Peterse1190062001-01-15 03:34:38 +0000279
Guido van Rossum731630b1996-08-19 22:26:43 +0000280if __name__ == '__main__':
Guido van Rossum72fba791996-08-19 22:49:35 +0000281 _test()