
import PyIDL as CORBA
import struct
import StringIO

class OutputBuffer(object):

	def __init__(self, buf=None):
		if buf is None :
			buf = StringIO.StringIO()
		self._buf = buf
		self._pos = 0
		self._endian = 1	# little endian

	def _get_endian(self):
		return self._endian

	endian = property(fget=_get_endian)

	def getvalue(self):
		return self._buf.getvalue()

	def close(self):
		self._buf.close()

	def write(self, str):
		self._buf.write(str)

	def _align(self, size):
		while (self._pos % size) != 0 :
			self._buf.write(chr(0))
			self._pos += 1

	def _pack(self, fmt, value):
		str = struct.pack(fmt, value)
		self._buf.write(str)
		self._pos += len(str)

	def char__marshal(self, value):
		self._pack('c', value)

	def wchar__marshal(self, value):
		raise NotImplementedError

	def octet__marshal(self, value):
		self._pack('B', value)

	def short__marshal(self, value):
		self._align(2)
		self._pack('h', value)

	def unsigned_short__marshal(self, value):
		self._align(2)
		self._pack('H', value)

	def long__marshal(self, value):
		self._align(4)
		self._pack('l', value)

	def unsigned_long__marshal(self, value):
		self._align(4)
		self._pack('L', value)

	def long_long__marshal(self, value):
		raise NotImplementedError

	def unsigned_long_long__marshal(self, value):
		raise NotImplementedError

	def float__marshal(self, value):
		self._align(4)
		self._pack('f', value)

	def double__marshal(self, value):
		self._align(8)
		self._pack('d', value)

	def long_double__marshal(self, value):
		raise NotImplementedError

	def boolean__marshal(self, value):
		if value == True :
			self._pack('B', 1)
		else :
			self._pack('B', 0)

	def string__marshal(self, value):
		self._align(4)
		value += chr(0)
		length = len(value)
		self._pack('L', length)
		self._pack(str(length) + 's', value)

	def wstring__marshal(self, value):
		raise NotImplementedError


class InputBuffer(object):

	def __init__(self, input=None, endian=None):
		if input == None :
			self._buf = StringIO.StringIO('')
		if isinstance(input, str) :
			self._buf = StringIO.StringIO(input)
 		else :
			self._buf = input
		self._pos = 0
		self._endian = endian

	def _set_endian(self, value):
		self._endian = value

	def _get_endian(self):
		return self._endian

	endian = property(fset=_set_endian, fget=_get_endian)

	def getvalue(self):
		return self._buf.getvalue()

	def close(self):
		self._buf.close()

	def read(self, size=-1):
		return self._buf.read(size)

	def _align(self, size):
		while (self._pos % size) != 0 :
			dummy = self._buf.read(1)
			self._pos += 1

	def _unpack(self, fmt):
		size = struct.calcsize(fmt)
		chunk = self._buf.read(size)
		if len(chunk) < size :
			print "Not enough data!"
			raise CORBA.SystemException("IDL:CORBA/INTERNAL:1.0", 8, CORBA_COMPLETED_MAYBE)
		self._pos += size
		return struct.unpack(fmt, chunk)[0]

	def char__demarshal(self):
		return self._unpack('c')

	def wchar__demarshal(self):
		raise NotImplementedError

	def octet__demarshal(self):
		return self._unpack('B')

	def short__demarshal(self):
		self._align(2)
		return self._unpack('h')

	def unsigned_short__demarshal(self):
		self._align(2)
		return self._unpack('H')

	def long__demarshal(self):
		self._align(4)
		return self._unpack('l')

	def unsigned_long__demarshal(self):
		self._align(4)
		return self._unpack('L')

	def long_long__demarshal(self):
		raise NotImplementedError

	def unsigned_long_long__demarshal(self):
		raise NotImplementedError

	def float__demarshal(self):
		self._align(4)
		return self._unpack('f')

	def double__demarshal(self):
		self._align(8)
		return self._unpack('d')

	def long_double__demarshal(self):
		raise NotImplementedError

	def boolean__demarshal(self):
		return self._unpack('B') == 1

	def string__demarshal(self):
		self._align(4)
		length = self._unpack('L')
		s = self._unpack(str(length) + 's')
		return s[:len(s)-1]

	def wstring__demarshal(self):
		raise NotImplementedError

