@@ -38,14 +38,32 @@ def from_file(cls, filename):
38
38
f .close ()
39
39
raise
40
40
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
+
41
51
@classmethod
42
52
def from_bytes (cls , buf ):
43
53
return cls (KaitaiStream (BytesIO (buf )))
44
54
55
+ @classmethod
56
+ def to_bytes (cls , buf , data = None ):
57
+ return cls (KaitaiStream (BytesIO (buf )), _mode = 'w' , _data = data )
58
+
45
59
@classmethod
46
60
def from_io (cls , io ):
47
61
return cls (KaitaiStream (io ))
48
62
63
+ @classmethod
64
+ def to_io (cls , io , data = None ):
65
+ return cls (KaitaiStream (io ), _mode = 'w' , _data = data )
66
+
49
67
50
68
class KaitaiStream (object ):
51
69
def __init__ (self , io ):
@@ -125,6 +143,9 @@ def size(self):
125
143
def read_s1 (self ):
126
144
return KaitaiStream .packer_s1 .unpack (self .read_bytes (1 ))[0 ]
127
145
146
+ def write_s1 (self , data ):
147
+ return self .write_bytes (KaitaiStream .packer_s1 .pack (data ))
148
+
128
149
# ........................................................................
129
150
# Big-endian
130
151
# ........................................................................
@@ -138,6 +159,15 @@ def read_s4be(self):
138
159
def read_s8be (self ):
139
160
return KaitaiStream .packer_s8be .unpack (self .read_bytes (8 ))[0 ]
140
161
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
+
141
171
# ........................................................................
142
172
# Little-endian
143
173
# ........................................................................
@@ -151,13 +181,25 @@ def read_s4le(self):
151
181
def read_s8le (self ):
152
182
return KaitaiStream .packer_s8le .unpack (self .read_bytes (8 ))[0 ]
153
183
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
+
154
193
# ------------------------------------------------------------------------
155
194
# Unsigned
156
195
# ------------------------------------------------------------------------
157
196
158
197
def read_u1 (self ):
159
198
return KaitaiStream .packer_u1 .unpack (self .read_bytes (1 ))[0 ]
160
199
200
+ def write_u1 (self , data ):
201
+ return self .write_bytes (KaitaiStream .packer_u1 .pack (data ))
202
+
161
203
# ........................................................................
162
204
# Big-endian
163
205
# ........................................................................
@@ -171,6 +213,15 @@ def read_u4be(self):
171
213
def read_u8be (self ):
172
214
return KaitaiStream .packer_u8be .unpack (self .read_bytes (8 ))[0 ]
173
215
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
+
174
225
# ........................................................................
175
226
# Little-endian
176
227
# ........................................................................
@@ -184,6 +235,15 @@ def read_u4le(self):
184
235
def read_u8le (self ):
185
236
return KaitaiStream .packer_u8le .unpack (self .read_bytes (8 ))[0 ]
186
237
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
+
187
247
# ========================================================================
188
248
# Floating point numbers
189
249
# ========================================================================
@@ -203,6 +263,12 @@ def read_f4be(self):
203
263
def read_f8be (self ):
204
264
return KaitaiStream .packer_f8be .unpack (self .read_bytes (8 ))[0 ]
205
265
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
+
206
272
# ........................................................................
207
273
# Little-endian
208
274
# ........................................................................
@@ -213,6 +279,12 @@ def read_f4le(self):
213
279
def read_f8le (self ):
214
280
return KaitaiStream .packer_f8le .unpack (self .read_bytes (8 ))[0 ]
215
281
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
+
216
288
# ========================================================================
217
289
# Unaligned bit values
218
290
# ========================================================================
@@ -279,7 +351,10 @@ def read_bits_int_le(self, n):
279
351
# Byte arrays
280
352
# ========================================================================
281
353
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 ):
283
358
if n < 0 :
284
359
raise ValueError (
285
360
"requested invalid %d amount of bytes" %
@@ -291,15 +366,31 @@ def read_bytes(self, n):
291
366
"requested %d bytes, but got only %d bytes" %
292
367
(n , len (r ))
293
368
)
369
+ if align > 1 :
370
+ self ._io .seek (self .alignment (align ), 1 )
294
371
return r
295
372
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
+
296
387
def read_bytes_full (self ):
297
388
return self ._io .read ()
298
389
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 ):
300
391
r = b''
301
392
while True :
302
- c = self ._io .read (1 )
393
+ c = self ._io .read (elem_size )
303
394
if c == b'' :
304
395
if eos_error :
305
396
raise Exception (
@@ -312,11 +403,14 @@ def read_bytes_term(self, term, include_term, consume_term, eos_error):
312
403
if include_term :
313
404
r += c
314
405
if not consume_term :
315
- self ._io .seek (- 1 , SEEK_CUR )
406
+ self ._io .seek (- elem_size , SEEK_CUR )
316
407
return r
317
408
else :
318
409
r += c
319
410
411
+ def write_bytes_term (self , data , term = b'\0 ' , align = 0 ):
412
+ self .write_bytes (data , align = align , pad = 1 , padding = term )
413
+
320
414
def ensure_fixed_contents (self , expected ):
321
415
actual = self ._io .read (len (expected ))
322
416
if actual != expected :
@@ -327,7 +421,7 @@ def ensure_fixed_contents(self, expected):
327
421
return actual
328
422
329
423
@staticmethod
330
- def bytes_strip_right (data , pad_byte ):
424
+ def bytes_strip_right (data , pad_byte = b' \0 ' ):
331
425
new_len = len (data )
332
426
if PY2 :
333
427
# data[...] must yield an integer, to compare with integer pad_byte
@@ -339,18 +433,18 @@ def bytes_strip_right(data, pad_byte):
339
433
return data [:new_len ]
340
434
341
435
@staticmethod
342
- def bytes_terminate (data , term , include_term ):
436
+ def bytes_terminate (data , term , include_term = True , elem_size = 1 ):
343
437
new_len = 0
344
438
max_len = len (data )
345
439
if PY2 :
346
440
# data[...] must yield an integer, to compare with integer term
347
441
data = bytearray (data )
348
442
349
443
while new_len < max_len and data [new_len ] != term :
350
- new_len += 1
444
+ new_len += elem_size
351
445
352
446
if include_term and new_len < max_len :
353
- new_len += 1
447
+ new_len += elem_size
354
448
355
449
return data [:new_len ]
356
450
0 commit comments