class QemuEncoder(object):
    def __init__(self):
        self.buf = []

    def __check(self, v, max):
        if v > max or v < 0:
            raise ValueError, \
                  "v must be between 0 and 0x%X, got 0x%X" % (max, v)

    def put_byte(self, v):
        self.__check(v, 0xFF)
        self.buf.append(chr(v))

    def put_be16(self, v):
        self.__check(v, 0xFFFF)
        self.put_byte(v & 0xFF)
        self.put_byte((v >> 8) & 0xFF)

    def put_be32(self, v):
        self.__check(v, 0xFFFFFFFFL)
        self.put_be16(v & 0xFFFF)
        self.put_be16((v >> 16) & 0xFFFF)

    def put_be64(self, v):
        self.__check(v, 0xFFFFFFFFFFFFFFFFL)
        self.put_be32(v & 0xFFFFFFFFL)
        self.put_be32((v >> 32) & 0xFFFFFFFFL)

    def put_buffer(self, v):
        if not isinstance(v, str):
            raise ValueError, "Buffer must be a string object"
        self.buf.append(v)

    def put_string(self, v):
        if not isinstance(v, str):
            raise ValueError, "Buffer must be a string object"
        self.put_be32(len(v))
        self.put_buffer(v)

    def __str__(self):
        return "".join(self.buf)

class QemuDecoder(object):
    def __init__(self, buf):
        self.buf = [ord(x) for x in buf]
        self.pos = 0

    def get_byte(self):
        v = self.buf[self.pos]
        self.pos += 1
        return v

    def get_be16(self):
        return self.get_byte() | (self.get_byte() << 8)

    def get_be32(self):
        return self.get_be16() | (long(self.get_be16()) << 16)

    def get_be64(self):
        return self.get_be32() | (self.get_be32() << 32)

    def get_buffer(self, length = None):
        if length is None:
            ret = "".join([chr(x) for x in self.buf[self.pos:]])
            self.pos = len(self.buf)
        else:
            ret = "".join([chr(x) for x in self.buf[self.pos:self.pos+length]])
            self.pos += length
        return ret

    def get_string(self):
        l = self.get_be32()
        v = self.get_buffer(l)
        if len(v) != l:
            raise RuntimeError, \
                  "Incomplete string retrieved, expected %d bytes, got %d" % \
                  (l, len(v))
        return v
