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.

224 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. return struct.unpack('>L', data)[0]
  104. def unpack_int(self):
  105. i = self.__pos
  106. self.__pos = j = i+4
  107. data = self.__buf[i:j]
  108. if len(data) < 4:
  109. raise EOFError
  110. return struct.unpack('>l', data)[0]
  111. unpack_enum = unpack_int
  112. def unpack_bool(self):
  113. return bool(self.unpack_int())
  114. def unpack_uhyper(self):
  115. hi = self.unpack_uint()
  116. lo = self.unpack_uint()
  117. return int(hi)<<32 | lo
  118. def unpack_hyper(self):
  119. x = self.unpack_uhyper()
  120. if x >= 0x8000000000000000:
  121. x = x - 0x10000000000000000
  122. return x
  123. def unpack_float(self):
  124. i = self.__pos
  125. self.__pos = j = i+4
  126. data = self.__buf[i:j]
  127. if len(data) < 4:
  128. raise EOFError
  129. return struct.unpack('>f', data)[0]
  130. def unpack_double(self):
  131. i = self.__pos
  132. self.__pos = j = i+8
  133. data = self.__buf[i:j]
  134. if len(data) < 8:
  135. raise EOFError
  136. return struct.unpack('>d', data)[0]
  137. def unpack_fstring(self, n):
  138. if n < 0:
  139. raise ValueError('fstring size must be nonnegative')
  140. i = self.__pos
  141. j = i + (n+3)//4*4
  142. if j > len(self.__buf):
  143. raise EOFError
  144. self.__pos = j
  145. return self.__buf[i:i+n]
  146. unpack_fopaque = unpack_fstring
  147. def unpack_string(self):
  148. n = self.unpack_uint()
  149. return self.unpack_fstring(n)
  150. unpack_opaque = unpack_string
  151. unpack_bytes = unpack_string
  152. def unpack_list(self, unpack_item):
  153. list = []
  154. while 1:
  155. x = self.unpack_uint()
  156. if x == 0: break
  157. if x != 1:
  158. raise ConversionError('0 or 1 expected, got %r' % (x,))
  159. item = unpack_item()
  160. list.append(item)
  161. return list
  162. def unpack_farray(self, n, unpack_item):
  163. list = []
  164. for i in range(n):
  165. list.append(unpack_item())
  166. return list
  167. def unpack_array(self, unpack_item):
  168. n = self.unpack_uint()
  169. return self.unpack_farray(n, unpack_item)