xdrlib.py 5.8 KB

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