1 from struct import pack, unpack, calcsize
3 class fmterror(Exception):
6 class eomerror(fmterror):
19 while (c < 7) and (b & (1 << (6 - c))):
21 if c == 0 or c == 7: raise fmterror("invalid utf8 start-byte")
22 iacc = acc = b & ((1 << (6 - c)) - 1)
25 if i >= len(bs): raise fmterror("unterminated utf8 compound")
28 if b & 0xc0 != 0x80: raise fmterror("invalid utf8 continuation byte")
29 acc = (acc << 6) | b & 0x3f
31 if iacc == 0 and ic != 2 and acc != 0: raise fmterror("invalid utf8 compound")
40 ret.extend(b"\xc0\x80")
44 ret.append(0xc0 | ((c & 0x7c0) >> 6))
45 ret.append(0x80 | (c & 0x03f))
46 elif 2048 <= c < 65536:
47 ret.append(0xe0 | ((c & 0xf000) >> 12))
48 ret.append(0x80 | ((c & 0x0fc0) >> 6))
49 ret.append(0x80 | (c & 0x003f))
51 raise fmterror("non-BMP unicode not supported by Java")
54 class decoder(object):
55 def destruct(self, fmt):
56 return unpack(fmt, self.splice(calcsize(fmt)))
62 return self.destruct(">b")[0]
64 return self.destruct(">B")[0]
66 return self.destruct(">h")[0]
68 return self.destruct(">H")[0]
70 return self.destruct(">i")[0]
72 return self.destruct(">I")[0]
74 return self.destruct(">q")[0]
76 return self.destruct(">Q")[0]
78 return self.destruct(">f")[0]
80 return self.destruct(">d")[0]
82 class decstream(decoder):
83 def __init__(self, bk):
85 self.buf = bytearray()
90 ret = self.bk.read(1024)
96 def splice(self, ln=-1):
102 self.buf = bytearray()
107 rl = max(ln - len(buf), 1024)
108 ret = self.bk.read(rl)
110 raise eomerror("unexpected end-of-file")
113 return bytes(buf[:ln])
116 if ln < len(self.buf):
117 self.buf = self.buf[ln:]
120 self.buf = bytearray()
121 if hasattr(self.bk, "seek"):
122 self.bk.seek(ln - 1, 1)
123 if len(self.bk.read(1)) != 1:
124 raise eomerror("unexpected end-of-file")
129 raise eomerror("unexpected end-of-file")
136 p2 = buf.find(b'\0', p)
138 self.buf = buf[p2 + 1:]
139 return str(buf[:p2], "utf-8")
140 ret = self.bk.read(1024)
143 raise eomerror("unexpected end-of-file")
144 raise fmterror("no string terminator found")
154 def __exit__(self, *excinfo):
158 class decbuf(decoder):
159 def __init__(self, data):
164 return len(self.data) - self.offset
167 return self.offset >= len(self.data)
169 def splice(self, ln=-1):
171 ret = self.data[self.offset:]
172 self.offset = len(self.data)
175 if self.offset + ln > len(self.data):
176 raise eomerror("out of data to decode")
177 ret = self.data[self.offset:self.offset + ln]
182 p = self.data.find(b'\0', self.offset)
184 if self.offset == len(self.data):
185 raise eomerror("out of data to decode")
186 raise fmterror("no string terminator found")
187 ret = str(self.data[self.offset:p], "utf-8")
191 class encoder(object):
192 def enstruct(self, fmt, *args):
193 self.extend(pack(fmt, *args))
197 self.enstruct(">b", val)
199 def uint8(self, val):
200 self.enstruct(">B", val)
202 def int16(self, val):
203 self.enstruct(">h", val)
205 def uint16(self, val):
206 self.enstruct(">H", val)
208 def int32(self, val):
209 self.enstruct(">i", val)
211 def uint32(self, val):
212 self.enstruct(">I", val)
214 def int64(self, val):
215 self.enstruct(">q", val)
217 def uint64(self, val):
218 self.enstruct(">Q", val)
220 def float32(self, val):
221 self.enstruct(">f", val)
223 def float64(self, val):
224 self.enstruct(">d", val)
228 if val.find('\0') >= 0:
229 raise ValueError("encoded strings must not contain NULs")
230 self.extend(val.encode("utf-8"))
234 def ttol(self, val, term=False):
236 if isinstance(obj, int):
240 elif 0 <= obj < 65536:
246 elif isinstance(obj, str):
249 elif isinstance(obj, utils.coord):
252 elif isinstance(obj, utils.color):
255 elif isinstance(obj, list):
258 elif isinstance(obj, float):
259 self.uint8(T_FLOAT32)
263 elif isinstance(obj, collections.ByteString):
268 self.uint8(0x80).int32(len(obj))
271 raise ValueError("unexpected type in tto-list: %s" % type(obj))
276 class encstream(encoder):
277 def __init__(self, bk):
280 def extend(self, data):
290 def __exit__(self, *excinfo):
294 class encbuf(encoder, bytearray):
295 def extend(self, data):
296 bytearray.extend(self, data)