xdrlib.py 5.9 KB

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