xdr.py 4.92 KB
Newer Older
Guido van Rossum's avatar
Guido van Rossum committed
1 2 3
# Implement (a subset of) Sun XDR -- RFC1014.


4
try:
5
    import struct
6
except ImportError:
7
    struct = None
Guido van Rossum's avatar
Guido van Rossum committed
8 9


10 11 12
Long = type(0L)


Guido van Rossum's avatar
Guido van Rossum committed
13 14
class Packer:

15 16
    def __init__(self):
        self.reset()
Guido van Rossum's avatar
Guido van Rossum committed
17

18 19
    def reset(self):
        self.buf = ''
Guido van Rossum's avatar
Guido van Rossum committed
20

21 22
    def get_buf(self):
        return self.buf
Guido van Rossum's avatar
Guido van Rossum committed
23

24 25 26 27 28 29 30 31 32 33
    def pack_uint(self, x):
        self.buf = self.buf + \
                (chr(int(x>>24 & 0xff)) + chr(int(x>>16 & 0xff)) + \
                 chr(int(x>>8 & 0xff)) + chr(int(x & 0xff)))
    if struct and struct.pack('l', 1) == '\0\0\0\1':
        def pack_uint(self, x):
            if type(x) == Long:
                x = int((x + 0x80000000L) % 0x100000000L \
                           - 0x80000000L)
            self.buf = self.buf + struct.pack('l', x)
Guido van Rossum's avatar
Guido van Rossum committed
34

35
    pack_int = pack_uint
Guido van Rossum's avatar
Guido van Rossum committed
36

37
    pack_enum = pack_int
Guido van Rossum's avatar
Guido van Rossum committed
38

39 40 41
    def pack_bool(self, x):
        if x: self.buf = self.buf + '\0\0\0\1'
        else: self.buf = self.buf + '\0\0\0\0'
Guido van Rossum's avatar
Guido van Rossum committed
42

43 44 45
    def pack_uhyper(self, x):
        self.pack_uint(int(x>>32 & 0xffffffff))
        self.pack_uint(int(x & 0xffffffff))
Guido van Rossum's avatar
Guido van Rossum committed
46

47
    pack_hyper = pack_uhyper
Guido van Rossum's avatar
Guido van Rossum committed
48

49 50 51
    def pack_float(self, x):
        # XXX
        self.buf = self.buf + struct.pack('f', x)
52

53 54 55
    def pack_double(self, x):
        # XXX
        self.buf = self.buf + struct.pack('d', x)
56

57 58 59 60 61 62 63
    def pack_fstring(self, n, s):
        if n < 0:
            raise ValueError, 'fstring size must be nonnegative'
        n = ((n+3)/4)*4
        data = s[:n]
        data = data + (n - len(data)) * '\0'
        self.buf = self.buf + data
Guido van Rossum's avatar
Guido van Rossum committed
64

65
    pack_fopaque = pack_fstring
Guido van Rossum's avatar
Guido van Rossum committed
66

67 68 69 70
    def pack_string(self, s):
        n = len(s)
        self.pack_uint(n)
        self.pack_fstring(n, s)
Guido van Rossum's avatar
Guido van Rossum committed
71

72
    pack_opaque = pack_string
Guido van Rossum's avatar
Guido van Rossum committed
73

74 75 76 77 78
    def pack_list(self, list, pack_item):
        for item in list:
            self.pack_uint(1)
            pack_item(item)
        self.pack_uint(0)
Guido van Rossum's avatar
Guido van Rossum committed
79

80 81 82 83 84
    def pack_farray(self, n, list, pack_item):
        if len(list) <> n:
            raise ValueError, 'wrong array size'
        for item in list:
            pack_item(item)
85

86 87 88 89
    def pack_array(self, list, pack_item):
        n = len(list)
        self.pack_uint(n)
        self.pack_farray(n, list, pack_item)
90

Guido van Rossum's avatar
Guido van Rossum committed
91 92 93

class Unpacker:

94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
    def __init__(self, data):
        self.reset(data)

    def reset(self, data):
        self.buf = data
        self.pos = 0

    def done(self):
        if self.pos < len(self.buf):
            raise RuntimeError, 'unextracted data remains'

    def unpack_uint(self):
        i = self.pos
        self.pos = j = i+4
        data = self.buf[i:j]
        if len(data) < 4:
            raise EOFError
        x = long(ord(data[0]))<<24 | ord(data[1])<<16 | \
                ord(data[2])<<8 | ord(data[3])
        # Return a Python long only if the value is not representable
        # as a nonnegative Python int
        if x < 0x80000000L: x = int(x)
        return x
    if struct and struct.unpack('l', '\0\0\0\1') == 1:
        def unpack_uint(self):
            i = self.pos
            self.pos = j = i+4
            data = self.buf[i:j]
            if len(data) < 4:
                raise EOFError
            return struct.unpack('l', data)

    def unpack_int(self):
        x = self.unpack_uint()
        if x >= 0x80000000L: x = x - 0x100000000L
        return int(x)

    unpack_enum = unpack_int

    unpack_bool = unpack_int

    def unpack_uhyper(self):
        hi = self.unpack_uint()
        lo = self.unpack_uint()
        return long(hi)<<32 | lo

    def unpack_hyper(self):
        x = self.unpack_uhyper()
        if x >= 0x8000000000000000L: x = x - 0x10000000000000000L
        return x

    def unpack_float(self):
        # XXX
        i = self.pos
        self.pos = j = i+4
        data = self.buf[i:j]
        if len(data) < 4:
            raise EOFError
        return struct.unpack('f', data)[0]

    def unpack_double(self):
        # XXX
        i = self.pos
        self.pos = j = i+8
        data = self.buf[i:j]
        if len(data) < 8:
            raise EOFError
        return struct.unpack('d', data)[0]

    def unpack_fstring(self, n):
        if n < 0:
            raise ValueError, 'fstring size must be nonnegative'
        i = self.pos
        j = i + (n+3)/4*4
        if j > len(self.buf):
            raise EOFError
        self.pos = j
        return self.buf[i:i+n]

    unpack_fopaque = unpack_fstring

    def unpack_string(self):
        n = self.unpack_uint()
        return self.unpack_fstring(n)

    unpack_opaque = unpack_string

    def unpack_list(self, unpack_item):
        list = []
        while 1:
            x = self.unpack_uint()
            if x == 0: break
            if x <> 1:
                raise RuntimeError, '0 or 1 expected, got %r' % (x, )
            item = unpack_item()
            list.append(item)
        return list

    def unpack_farray(self, n, unpack_item):
        list = []
        for i in range(n):
            list.append(unpack_item())
        return list

    def unpack_array(self, unpack_item):
        n = self.unpack_uint()
        return self.unpack_farray(n, unpack_item)