Skip to content

Commit 156427a

Browse files
Add methods for serialization
1 parent 4b97420 commit 156427a

File tree

1 file changed

+102
-8
lines changed

1 file changed

+102
-8
lines changed

kaitaistruct.py

+102-8
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,32 @@ def from_file(cls, filename):
3838
f.close()
3939
raise
4040

41+
@classmethod
42+
def to_file(cls, filename, data=None):
43+
f = open(filename, 'rb')
44+
try:
45+
return cls(KaitaiStream(f), _mode='w', _data=data)
46+
except Exception:
47+
# close file descriptor, then reraise the exception
48+
f.close()
49+
raise
50+
4151
@classmethod
4252
def from_bytes(cls, buf):
4353
return cls(KaitaiStream(BytesIO(buf)))
4454

55+
@classmethod
56+
def to_bytes(cls, buf, data=None):
57+
return cls(KaitaiStream(BytesIO(buf)), _mode='w', _data=data)
58+
4559
@classmethod
4660
def from_io(cls, io):
4761
return cls(KaitaiStream(io))
4862

63+
@classmethod
64+
def to_io(cls, io, data=None):
65+
return cls(KaitaiStream(io), _mode='w', _data=data)
66+
4967

5068
class KaitaiStream(object):
5169
def __init__(self, io):
@@ -125,6 +143,9 @@ def size(self):
125143
def read_s1(self):
126144
return KaitaiStream.packer_s1.unpack(self.read_bytes(1))[0]
127145

146+
def write_s1(self, data):
147+
return self.write_bytes(KaitaiStream.packer_s1.pack(data))
148+
128149
# ........................................................................
129150
# Big-endian
130151
# ........................................................................
@@ -138,6 +159,15 @@ def read_s4be(self):
138159
def read_s8be(self):
139160
return KaitaiStream.packer_s8be.unpack(self.read_bytes(8))[0]
140161

162+
def write_s2be(self, data):
163+
return self.write_bytes(KaitaiStream.packer_s2be.pack(data))
164+
165+
def write_s4be(self, data):
166+
return self.write_bytes(KaitaiStream.packer_s4be.pack(data))
167+
168+
def write_s8be(self, data):
169+
return self.write_bytes(KaitaiStream.packer_s8be.pack(data))
170+
141171
# ........................................................................
142172
# Little-endian
143173
# ........................................................................
@@ -151,13 +181,25 @@ def read_s4le(self):
151181
def read_s8le(self):
152182
return KaitaiStream.packer_s8le.unpack(self.read_bytes(8))[0]
153183

184+
def write_s2le(self, data):
185+
return self.write_bytes(KaitaiStream.packer_s2le.pack(data))
186+
187+
def write_s4le(self, data):
188+
return self.write_bytes(KaitaiStream.packer_s4le.pack(data))
189+
190+
def write_s8le(self, data):
191+
return self.write_bytes(KaitaiStream.packer_s8le.pack(data))
192+
154193
# ------------------------------------------------------------------------
155194
# Unsigned
156195
# ------------------------------------------------------------------------
157196

158197
def read_u1(self):
159198
return KaitaiStream.packer_u1.unpack(self.read_bytes(1))[0]
160199

200+
def write_u1(self, data):
201+
return self.write_bytes(KaitaiStream.packer_u1.pack(data))
202+
161203
# ........................................................................
162204
# Big-endian
163205
# ........................................................................
@@ -171,6 +213,15 @@ def read_u4be(self):
171213
def read_u8be(self):
172214
return KaitaiStream.packer_u8be.unpack(self.read_bytes(8))[0]
173215

216+
def write_u2be(self, data):
217+
return self.write_bytes(KaitaiStream.packer_u2be.pack(data))
218+
219+
def write_u4be(self, data):
220+
return self.write_bytes(KaitaiStream.packer_u4be.pack(data))
221+
222+
def write_u8be(self, data):
223+
return self.write_bytes(KaitaiStream.packer_u8be.pack(data))
224+
174225
# ........................................................................
175226
# Little-endian
176227
# ........................................................................
@@ -184,6 +235,15 @@ def read_u4le(self):
184235
def read_u8le(self):
185236
return KaitaiStream.packer_u8le.unpack(self.read_bytes(8))[0]
186237

238+
def write_u2le(self, data):
239+
return self.write_bytes(KaitaiStream.packer_u2le.pack(data))
240+
241+
def write_u4le(self, data):
242+
return self.write_bytes(KaitaiStream.packer_u4le.pack(data))
243+
244+
def write_u8le(self, data):
245+
return self.write_bytes(KaitaiStream.packer_u8le.pack(data))
246+
187247
# ========================================================================
188248
# Floating point numbers
189249
# ========================================================================
@@ -203,6 +263,12 @@ def read_f4be(self):
203263
def read_f8be(self):
204264
return KaitaiStream.packer_f8be.unpack(self.read_bytes(8))[0]
205265

266+
def write_f4be(self, data):
267+
return self.write_bytes(KaitaiStream.packer_f4be.pack(data))
268+
269+
def write_f8be(self, data):
270+
return self.write_bytes(KaitaiStream.packer_f8be.pack(data))
271+
206272
# ........................................................................
207273
# Little-endian
208274
# ........................................................................
@@ -213,6 +279,12 @@ def read_f4le(self):
213279
def read_f8le(self):
214280
return KaitaiStream.packer_f8le.unpack(self.read_bytes(8))[0]
215281

282+
def write_f4le(self, data):
283+
return self.write_bytes(KaitaiStream.packer_f4le.pack(data))
284+
285+
def write_f8le(self, data):
286+
return self.write_bytes(KaitaiStream.packer_f8le.pack(data))
287+
216288
# ========================================================================
217289
# Unaligned bit values
218290
# ========================================================================
@@ -279,7 +351,10 @@ def read_bits_int_le(self, n):
279351
# Byte arrays
280352
# ========================================================================
281353

282-
def read_bytes(self, n):
354+
def alignment(self, a):
355+
return (a - self.pos()) % a
356+
357+
def read_bytes(self, n, align=0):
283358
if n < 0:
284359
raise ValueError(
285360
"requested invalid %d amount of bytes" %
@@ -291,15 +366,31 @@ def read_bytes(self, n):
291366
"requested %d bytes, but got only %d bytes" %
292367
(n, len(r))
293368
)
369+
if align > 1:
370+
self._io.seek(self.alignment(align), 1)
294371
return r
295372

373+
def write_bytes(self, data, align=0, pad=0, padding=b'\0'):
374+
if data is None:
375+
return
376+
nb = len(data)
377+
if nb == 0 and align < 2 and pad < 1:
378+
return
379+
if self._io.write(data) != nb:
380+
raise Exception("not all bytes written")
381+
if pad > 0:
382+
self._io.write(padding * pad)
383+
if align > 1:
384+
self._io.write(padding * self.alignment(align))
385+
return
386+
296387
def read_bytes_full(self):
297388
return self._io.read()
298389

299-
def read_bytes_term(self, term, include_term, consume_term, eos_error):
390+
def read_bytes_term(self, term, include_term=False, consume_term=True, eos_error=True, elem_size=1):
300391
r = b''
301392
while True:
302-
c = self._io.read(1)
393+
c = self._io.read(elem_size)
303394
if c == b'':
304395
if eos_error:
305396
raise Exception(
@@ -312,11 +403,14 @@ def read_bytes_term(self, term, include_term, consume_term, eos_error):
312403
if include_term:
313404
r += c
314405
if not consume_term:
315-
self._io.seek(-1, SEEK_CUR)
406+
self._io.seek(-elem_size, SEEK_CUR)
316407
return r
317408
else:
318409
r += c
319410

411+
def write_bytes_term(self, data, term=b'\0', align=0):
412+
self.write_bytes(data, align=align, pad=1, padding=term)
413+
320414
def ensure_fixed_contents(self, expected):
321415
actual = self._io.read(len(expected))
322416
if actual != expected:
@@ -327,7 +421,7 @@ def ensure_fixed_contents(self, expected):
327421
return actual
328422

329423
@staticmethod
330-
def bytes_strip_right(data, pad_byte):
424+
def bytes_strip_right(data, pad_byte=b'\0'):
331425
new_len = len(data)
332426
if PY2:
333427
# data[...] must yield an integer, to compare with integer pad_byte
@@ -339,18 +433,18 @@ def bytes_strip_right(data, pad_byte):
339433
return data[:new_len]
340434

341435
@staticmethod
342-
def bytes_terminate(data, term, include_term):
436+
def bytes_terminate(data, term, include_term=True, elem_size=1):
343437
new_len = 0
344438
max_len = len(data)
345439
if PY2:
346440
# data[...] must yield an integer, to compare with integer term
347441
data = bytearray(data)
348442

349443
while new_len < max_len and data[new_len] != term:
350-
new_len += 1
444+
new_len += elem_size
351445

352446
if include_term and new_len < max_len:
353-
new_len += 1
447+
new_len += elem_size
354448

355449
return data[:new_len]
356450

0 commit comments

Comments
 (0)