/Lib/xdrlib.py

http://unladen-swallow.googlecode.com/ · Python · 229 lines · 162 code · 49 blank · 18 comment · 26 complexity · a3c4f04ce6c376596f418907b6bbb41e MD5 · raw file

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