]> arthur.barton.de Git - bup.git/blob - lib/bup/vint.py
vint: remove unnecessary condition
[bup.git] / lib / bup / vint.py
1 """Binary encodings for bup."""
2
3 # Copyright (C) 2010 Rob Browning
4 #
5 # This code is covered under the terms of the GNU Library General
6 # Public License as described in the bup LICENSE file.
7
8 # Variable length integers are encoded as vints -- see lucene.
9
10 from __future__ import absolute_import
11 from io import BytesIO
12 import sys
13
14 from bup import compat
15
16
17 def write_vuint(port, x):
18     write = port.write
19     bytes_from_uint = compat.bytes_from_uint
20     if x < 0:
21         raise Exception("vuints must not be negative")
22     elif x == 0:
23         write(bytes_from_uint(0))
24     else:
25         while True:
26             seven_bits = x & 0x7f
27             x >>= 7
28             if x:
29                 write(bytes_from_uint(0x80 | seven_bits))
30             else:
31                 write(bytes_from_uint(seven_bits))
32                 break
33
34
35 def read_vuint(port):
36     c = port.read(1)
37     if not c:
38         raise EOFError('encountered EOF while reading vuint')
39     assert isinstance(c, bytes)
40     if ord(c) == 0:
41         return 0
42     result = 0
43     offset = 0
44     while True:
45         b = ord(c)
46         if b & 0x80:
47             result |= ((b & 0x7f) << offset)
48             offset += 7
49             c = port.read(1)
50             if not c:
51                 raise EOFError('encountered EOF while reading vuint')
52         else:
53             result |= (b << offset)
54             break
55     return result
56
57
58 def write_vint(port, x):
59     # Sign is handled with the second bit of the first byte.  All else
60     # matches vuint.
61     write = port.write
62     bytes_from_uint = compat.bytes_from_uint
63     if x == 0:
64         write(bytes_from_uint(0))
65     else:
66         if x < 0:
67             x = -x
68             sign_and_six_bits = (x & 0x3f) | 0x40
69         else:
70             sign_and_six_bits = x & 0x3f
71         x >>= 6
72         if x:
73             write(bytes_from_uint(0x80 | sign_and_six_bits))
74             write_vuint(port, x)
75         else:
76             write(bytes_from_uint(sign_and_six_bits))
77
78
79 def read_vint(port):
80     c = port.read(1)
81     if not c:
82         raise EOFError('encountered EOF while reading vint')
83     assert isinstance(c, bytes)
84     negative = False
85     result = 0
86     offset = 0
87     # Handle first byte with sign bit specially.
88     b = ord(c)
89     if b & 0x40:
90         negative = True
91     result |= (b & 0x3f)
92     if b & 0x80:
93         offset += 6
94         c = port.read(1)
95     elif negative:
96         return -result
97     else:
98         return result
99     while True:
100         b = ord(c)
101         if b & 0x80:
102             result |= ((b & 0x7f) << offset)
103             offset += 7
104             c = port.read(1)
105             if not c:
106                 raise EOFError('encountered EOF while reading vint')
107         else:
108             result |= (b << offset)
109             break
110     if negative:
111         return -result
112     else:
113         return result
114
115
116 def write_bvec(port, x):
117     write_vuint(port, len(x))
118     port.write(x)
119
120
121 def read_bvec(port):
122     n = read_vuint(port)
123     return port.read(n)
124
125
126 def skip_bvec(port):
127     port.read(read_vuint(port))
128
129 def send(port, types, *args):
130     if len(types) != len(args):
131         raise Exception('number of arguments does not match format string')
132     for (type, value) in zip(types, args):
133         if type == 'V':
134             write_vuint(port, value)
135         elif type == 'v':
136             write_vint(port, value)
137         elif type == 's':
138             write_bvec(port, value)
139         else:
140             raise Exception('unknown xpack format string item "' + type + '"')
141
142 def recv(port, types):
143     result = []
144     for type in types:
145         if type == 'V':
146             result.append(read_vuint(port))
147         elif type == 'v':
148             result.append(read_vint(port))
149         elif type == 's':
150             result.append(read_bvec(port))
151         else:
152             raise Exception('unknown xunpack format string item "' + type + '"')
153     return result
154
155 def pack(types, *args):
156     port = BytesIO()
157     send(port, types, *args)
158     return port.getvalue()
159
160 def unpack(types, data):
161     port = BytesIO(data)
162     return recv(port, types)