xdrlib.py 5.8 KB

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