blob: d6e1aeb527266af97f0338806a673894ec2f3c64 [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
Brett Cannon1eb79cf2007-07-26 03:19:46 +00008from io import BytesIO
Petri Lehtinen3894b2a2014-10-10 21:21:52 +03009from functools import wraps
Guido van Rossum731630b1996-08-19 22:26:43 +000010
Skip Montanaro40fc1602001-03-01 04:27:19 +000011__all__ = ["Error", "Packer", "Unpacker", "ConversionError"]
12
Guido van Rossum731630b1996-08-19 22:26:43 +000013# exceptions
Neal Norwitzf74e46c2002-03-31 13:59:18 +000014class Error(Exception):
Guido van Rossum731630b1996-08-19 22:26:43 +000015 """Exception class for this module. Use:
16
Andrew Svetlov42d5c412012-11-01 13:43:06 +020017 except xdrlib.Error as var:
Guido van Rossum731630b1996-08-19 22:26:43 +000018 # var has the Error instance for the exception
19
20 Public ivars:
21 msg -- contains the message
22
23 """
24 def __init__(self, msg):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000025 self.msg = msg
Guido van Rossum731630b1996-08-19 22:26:43 +000026 def __repr__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000027 return repr(self.msg)
Guido van Rossum731630b1996-08-19 22:26:43 +000028 def __str__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000029 return str(self.msg)
Guido van Rossum731630b1996-08-19 22:26:43 +000030
31
32class ConversionError(Error):
33 pass
34
Petri Lehtinen3894b2a2014-10-10 21:21:52 +030035def raise_conversion_error(function):
36 """ Wrap any raised struct.errors in a ConversionError. """
37
38 @wraps(function)
39 def result(self, value):
40 try:
41 return function(self, value)
42 except struct.error as e:
43 raise ConversionError(e.args[0]) from None
44 return result
Guido van Rossum731630b1996-08-19 22:26:43 +000045
Tim Peterse1190062001-01-15 03:34:38 +000046
Guido van Rossum731630b1996-08-19 22:26:43 +000047class Packer:
48 """Pack various data representations into a buffer."""
49
50 def __init__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000051 self.reset()
Guido van Rossum731630b1996-08-19 22:26:43 +000052
53 def reset(self):
Brett Cannon1eb79cf2007-07-26 03:19:46 +000054 self.__buf = BytesIO()
Guido van Rossum731630b1996-08-19 22:26:43 +000055
56 def get_buffer(self):
Martin v. Löwisc47016e2001-08-16 17:06:44 +000057 return self.__buf.getvalue()
Guido van Rossum731630b1996-08-19 22:26:43 +000058 # backwards compatibility
59 get_buf = get_buffer
60
Petri Lehtinen3894b2a2014-10-10 21:21:52 +030061 @raise_conversion_error
Guido van Rossum731630b1996-08-19 22:26:43 +000062 def pack_uint(self, x):
Martin v. Löwisc47016e2001-08-16 17:06:44 +000063 self.__buf.write(struct.pack('>L', x))
Guido van Rossum731630b1996-08-19 22:26:43 +000064
Petri Lehtinen3894b2a2014-10-10 21:21:52 +030065 @raise_conversion_error
Mark Dickinson92b60d52011-03-27 16:25:40 +010066 def pack_int(self, x):
67 self.__buf.write(struct.pack('>l', x))
68
Guido van Rossum731630b1996-08-19 22:26:43 +000069 pack_enum = pack_int
70
71 def pack_bool(self, x):
Brett Cannon1eb79cf2007-07-26 03:19:46 +000072 if x: self.__buf.write(b'\0\0\0\1')
73 else: self.__buf.write(b'\0\0\0\0')
Guido van Rossum731630b1996-08-19 22:26:43 +000074
75 def pack_uhyper(self, x):
Petri Lehtinen3894b2a2014-10-10 21:21:52 +030076 try:
77 self.pack_uint(x>>32 & 0xffffffff)
78 except (TypeError, struct.error) as e:
79 raise ConversionError(e.args[0]) from None
80 try:
81 self.pack_uint(x & 0xffffffff)
82 except (TypeError, struct.error) as e:
83 raise ConversionError(e.args[0]) from None
Guido van Rossum731630b1996-08-19 22:26:43 +000084
85 pack_hyper = pack_uhyper
86
Petri Lehtinen3894b2a2014-10-10 21:21:52 +030087 @raise_conversion_error
Guido van Rossum731630b1996-08-19 22:26:43 +000088 def pack_float(self, x):
Petri Lehtinen3894b2a2014-10-10 21:21:52 +030089 self.__buf.write(struct.pack('>f', x))
Guido van Rossum6083f0e1997-01-02 22:52:15 +000090
Petri Lehtinen3894b2a2014-10-10 21:21:52 +030091 @raise_conversion_error
Guido van Rossum731630b1996-08-19 22:26:43 +000092 def pack_double(self, x):
Petri Lehtinen3894b2a2014-10-10 21:21:52 +030093 self.__buf.write(struct.pack('>d', x))
Guido van Rossum731630b1996-08-19 22:26:43 +000094
95 def pack_fstring(self, n, s):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000096 if n < 0:
Collin Winterce36ad82007-08-30 01:19:48 +000097 raise ValueError('fstring size must be nonnegative')
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000098 data = s[:n]
Thomas Wouters4f564bd2006-04-20 22:36:57 +000099 n = ((n+3)//4)*4
Brett Cannon1eb79cf2007-07-26 03:19:46 +0000100 data = data + (n - len(data)) * b'\0'
Martin v. Löwisc47016e2001-08-16 17:06:44 +0000101 self.__buf.write(data)
Guido van Rossum731630b1996-08-19 22:26:43 +0000102
103 pack_fopaque = pack_fstring
104
105 def pack_string(self, s):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000106 n = len(s)
107 self.pack_uint(n)
108 self.pack_fstring(n, s)
Guido van Rossum731630b1996-08-19 22:26:43 +0000109
110 pack_opaque = pack_string
111 pack_bytes = pack_string
112
113 def pack_list(self, list, pack_item):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000114 for item in list:
115 self.pack_uint(1)
116 pack_item(item)
117 self.pack_uint(0)
Guido van Rossum731630b1996-08-19 22:26:43 +0000118
119 def pack_farray(self, n, list, pack_item):
Fred Drake8152d322000-12-12 23:20:45 +0000120 if len(list) != n:
Collin Winterce36ad82007-08-30 01:19:48 +0000121 raise ValueError('wrong array size')
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000122 for item in list:
123 pack_item(item)
Guido van Rossum731630b1996-08-19 22:26:43 +0000124
125 def pack_array(self, list, pack_item):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000126 n = len(list)
127 self.pack_uint(n)
128 self.pack_farray(n, list, pack_item)
Guido van Rossum731630b1996-08-19 22:26:43 +0000129
130
Tim Peterse1190062001-01-15 03:34:38 +0000131
Guido van Rossum731630b1996-08-19 22:26:43 +0000132class Unpacker:
133 """Unpacks various data representations from the given buffer."""
134
135 def __init__(self, data):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000136 self.reset(data)
Guido van Rossum731630b1996-08-19 22:26:43 +0000137
138 def reset(self, data):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000139 self.__buf = data
140 self.__pos = 0
Guido van Rossum731630b1996-08-19 22:26:43 +0000141
142 def get_position(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000143 return self.__pos
Guido van Rossum731630b1996-08-19 22:26:43 +0000144
145 def set_position(self, position):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000146 self.__pos = position
Guido van Rossum731630b1996-08-19 22:26:43 +0000147
Barry Warsaw75eccc51996-12-04 22:04:39 +0000148 def get_buffer(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000149 return self.__buf
Barry Warsaw75eccc51996-12-04 22:04:39 +0000150
Guido van Rossum731630b1996-08-19 22:26:43 +0000151 def done(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000152 if self.__pos < len(self.__buf):
153 raise Error('unextracted data remains')
Guido van Rossum731630b1996-08-19 22:26:43 +0000154
155 def unpack_uint(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000156 i = self.__pos
157 self.__pos = j = i+4
158 data = self.__buf[i:j]
159 if len(data) < 4:
160 raise EOFError
Florent Xicluna2bb96f52011-10-23 22:11:00 +0200161 return struct.unpack('>L', data)[0]
Guido van Rossum731630b1996-08-19 22:26:43 +0000162
163 def unpack_int(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000164 i = self.__pos
165 self.__pos = j = i+4
166 data = self.__buf[i:j]
167 if len(data) < 4:
168 raise EOFError
169 return struct.unpack('>l', data)[0]
Guido van Rossum731630b1996-08-19 22:26:43 +0000170
171 unpack_enum = unpack_int
Martin v. Löwisc2a0ac22005-02-24 20:22:10 +0000172
173 def unpack_bool(self):
174 return bool(self.unpack_int())
Guido van Rossum731630b1996-08-19 22:26:43 +0000175
176 def unpack_uhyper(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000177 hi = self.unpack_uint()
178 lo = self.unpack_uint()
Guido van Rossume2a383d2007-01-15 16:59:06 +0000179 return int(hi)<<32 | lo
Guido van Rossum731630b1996-08-19 22:26:43 +0000180
181 def unpack_hyper(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000182 x = self.unpack_uhyper()
Guido van Rossume2a383d2007-01-15 16:59:06 +0000183 if x >= 0x8000000000000000:
184 x = x - 0x10000000000000000
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000185 return x
Guido van Rossum731630b1996-08-19 22:26:43 +0000186
187 def unpack_float(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000188 i = self.__pos
189 self.__pos = j = i+4
190 data = self.__buf[i:j]
191 if len(data) < 4:
192 raise EOFError
193 return struct.unpack('>f', data)[0]
Guido van Rossum731630b1996-08-19 22:26:43 +0000194
Guido van Rossum6083f0e1997-01-02 22:52:15 +0000195 def unpack_double(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000196 i = self.__pos
197 self.__pos = j = i+8
198 data = self.__buf[i:j]
199 if len(data) < 8:
200 raise EOFError
201 return struct.unpack('>d', data)[0]
Guido van Rossum731630b1996-08-19 22:26:43 +0000202
203 def unpack_fstring(self, n):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000204 if n < 0:
Collin Winterce36ad82007-08-30 01:19:48 +0000205 raise ValueError('fstring size must be nonnegative')
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000206 i = self.__pos
Thomas Wouters4f564bd2006-04-20 22:36:57 +0000207 j = i + (n+3)//4*4
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000208 if j > len(self.__buf):
209 raise EOFError
210 self.__pos = j
211 return self.__buf[i:i+n]
Guido van Rossum731630b1996-08-19 22:26:43 +0000212
213 unpack_fopaque = unpack_fstring
214
215 def unpack_string(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000216 n = self.unpack_uint()
217 return self.unpack_fstring(n)
Guido van Rossum731630b1996-08-19 22:26:43 +0000218
219 unpack_opaque = unpack_string
220 unpack_bytes = unpack_string
221
222 def unpack_list(self, unpack_item):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000223 list = []
224 while 1:
225 x = self.unpack_uint()
226 if x == 0: break
Fred Drake8152d322000-12-12 23:20:45 +0000227 if x != 1:
Collin Winterce36ad82007-08-30 01:19:48 +0000228 raise ConversionError('0 or 1 expected, got %r' % (x,))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000229 item = unpack_item()
230 list.append(item)
231 return list
Guido van Rossum731630b1996-08-19 22:26:43 +0000232
233 def unpack_farray(self, n, unpack_item):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000234 list = []
235 for i in range(n):
236 list.append(unpack_item())
237 return list
Guido van Rossum731630b1996-08-19 22:26:43 +0000238
239 def unpack_array(self, unpack_item):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000240 n = self.unpack_uint()
241 return self.unpack_farray(n, unpack_item)