Added a distutils script.
[pycfml.git] / classfile / binfmt.py
CommitLineData
964561d6
FT
1from struct import pack, unpack, calcsize
2
3class fmterror(Exception):
4 pass
5
6class eomerror(fmterror):
7 pass
8
9def mutf8dec(bs):
10 ret = ""
11 i = 0
12 while i < len(bs):
13 b = bs[i]
14 i += 1
15 if b & 0x80 == 0:
16 ret += chr(b)
17 else:
18 c = 0
19 while (c < 7) and (b & (1 << (6 - c))):
20 c += 1
21 if c == 0 or c == 7: raise fmterror("invalid utf8 start-byte")
22 iacc = acc = b & ((1 << (6 - c)) - 1)
23 ic = c
24 while c > 0:
25 if i >= len(bs): raise fmterror("unterminated utf8 compound")
26 b = bs[i]
27 i += 1
28 if b & 0xc0 != 0x80: raise fmterror("invalid utf8 continuation byte")
29 acc = (acc << 6) | bs & 0x3f
30 c -= 1
31 if iacc == 0 and ic != 2 and acc != 0: raise fmterror("invalid utf8 compound")
32 ret += chr(acc)
33 return ret
34
35def mutf8enc(cs):
36 ret = bytearray()
37 for c in cs:
38 c = ord(c)
39 if c == 0:
40 ret.extend(b"\xc0\x80")
41 elif 1 <= c < 128:
42 ret.append(c)
43 elif 128 <= c < 2048:
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))
50 else:
51 raise fmterror("non-BMP unicode not supported by Java")
52 return bytes(ret)
53
54class decoder(object):
55 def destruct(self, fmt):
56 return unpack(fmt, self.splice(calcsize(fmt)))
57
58 def skip(self, ln):
59 self.splice(ln)
60
61 def int8(self):
62 return self.destruct(">b")[0]
63 def uint8(self):
64 return self.destruct(">B")[0]
65 def int16(self):
66 return self.destruct(">h")[0]
67 def uint16(self):
68 return self.destruct(">H")[0]
69 def int32(self):
70 return self.destruct(">i")[0]
71 def uint32(self):
72 return self.destruct(">I")[0]
73 def int64(self):
74 return self.destruct(">q")[0]
75 def uint64(self):
76 return self.destruct(">Q")[0]
77 def float32(self):
78 return self.destruct(">f")[0]
79 def float64(self):
80 return self.destruct(">d")[0]
81
82class decstream(decoder):
83 def __init__(self, bk):
84 self.bk = bk
85 self.buf = bytearray()
86
87 def eom(self):
88 if len(self.buf) > 0:
89 return False
90 ret = self.bk.read(1024)
91 if ret == b"":
92 return True
93 self.buf.extend(ret)
94 return False
95
96 def splice(self, ln=-1):
97 buf = self.buf
98 if ln < 0:
99 while True:
100 ret = self.bk.read()
101 if ret == b"":
102 self.buf = bytearray()
103 return bytes(buf)
104 buf.extend(ret)
105 else:
106 while len(buf) < ln:
107 rl = max(ln - len(buf), 1024)
108 ret = self.bk.read(rl)
109 if ret == b"":
110 raise eomerror("unexpected end-of-file")
111 buf.extend(ret)
112 self.buf = buf[ln:]
113 return bytes(buf[:ln])
114
115 def skip(self, ln):
116 if ln < len(self.buf):
117 self.buf = self.buf[ln:]
118 else:
119 ln -= len(self.buf)
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")
125 else:
126 while ln > 0:
127 r = self.bk.read(ln)
128 if r == b"":
129 raise eomerror("unexpected end-of-file")
130 ln -= len(r)
131
132 def str(self):
133 buf = self.buf
134 p = 0
135 while True:
136 p2 = buf.find(b'\0', p)
137 if p2 > 0:
138 self.buf = buf[p2 + 1:]
139 return str(buf[:p2], "utf-8")
140 ret = self.bk.read(1024)
141 if ret == b"":
142 if len(buf) == 0:
143 raise eomerror("unexpected end-of-file")
144 raise fmterror("no string terminator found")
145 p = len(buf)
146 buf.extend(ret)
147
148 def close(self):
149 self.bk.close()
150
151 def __enter__(self):
152 return self
153
154 def __exit__(self, *excinfo):
155 self.close()
156 return False
157
158class decbuf(decoder):
159 def __init__(self, data):
160 self.data = data
161 self.offset = 0
162
163 def __len__(self):
164 return len(self.data) - self.offset
165
166 def eom(self):
167 return self.offset >= len(self.data)
168
169 def splice(self, ln=-1):
170 if ln < 0:
171 ret = self.data[self.offset:]
172 self.offset = len(self.data)
173 return ret
174 else:
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]
178 self.offset += ln
179 return ret
180
181 def str(self):
182 p = self.data.find(b'\0', self.offset)
183 if p < 0:
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")
188 self.offset = p + 1
189 return str(ret)
190
191class encoder(object):
192 def enstruct(self, fmt, *args):
193 self.extend(pack(fmt, *args))
194 return self
195
196 def int8(self, val):
197 self.enstruct(">b", val)
198 return self
199 def uint8(self, val):
200 self.enstruct(">B", val)
201 return self
202 def int16(self, val):
203 self.enstruct(">h", val)
204 return self
205 def uint16(self, val):
206 self.enstruct(">H", val)
207 return self
208 def int32(self, val):
209 self.enstruct(">i", val)
210 return self
211 def uint32(self, val):
212 self.enstruct(">I", val)
213 return self
214 def int64(self, val):
215 self.enstruct(">q", val)
216 return self
217 def uint64(self, val):
218 self.enstruct(">Q", val)
219 return self
220 def float32(self, val):
221 self.enstruct(">f", val)
222 return self
223 def float64(self, val):
224 self.enstruct(">d", val)
225 return self
226
227 def str(self, val):
228 if val.find('\0') >= 0:
229 raise ValueError("encoded strings must not contain NULs")
230 self.extend(val.encode("utf-8"))
231 self.extend(b"\0")
232 return self
233
234 def ttol(self, val, term=False):
235 for obj in val:
236 if isinstance(obj, int):
237 if 0 <= obj < 256:
238 self.uint8(T_UINT8)
239 self.uint8(obj)
240 elif 0 <= obj < 65536:
241 self.uint8(T_UINT16)
242 self.uint16(obj)
243 else:
244 self.uint8(T_INT)
245 self.int32(obj)
246 elif isinstance(obj, str):
247 self.uint8(T_STR)
248 self.str(obj)
249 elif isinstance(obj, utils.coord):
250 self.uint8(T_COORD)
251 self.coord(obj)
252 elif isinstance(obj, utils.color):
253 self.uint8(T_COLOR)
254 self.color(obj)
255 elif isinstance(obj, list):
256 self.uint8(T_TTOL)
257 self.ttol(obj, True)
258 elif isinstance(obj, float):
259 self.uint8(T_FLOAT32)
260 self.float32(obj)
261 elif obj is None:
262 self.uint8(T_NIL)
263 elif isinstance(obj, collections.ByteString):
264 self.uint8(T_BYTES)
265 if len(obj) < 128:
266 self.uint8(len(obj))
267 else:
268 self.uint8(0x80).int32(len(obj))
269 self.extend(obj)
270 else:
271 raise ValueError("unexpected type in tto-list: %s" % type(obj))
272 if term:
273 self.uint8(T_END)
274 return self
275
276class encstream(encoder):
277 def __init__(self, bk):
278 self.bk = bk
279
280 def extend(self, data):
281 self.bk.write(data)
282 return self
283
284 def close(self):
285 self.bk.close()
286
287 def __enter__(self):
288 return self
289
290 def __exit__(self, *excinfo):
291 self.close()
292 return False
293
294class encbuf(encoder, bytearray):
295 def extend(self, data):
296 bytearray.extend(self, data)
297 return self