You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

228 lines
5.3 KiB

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