@@ -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
5068class 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