Skip to content

Commit e5bda2d

Browse files
committed
rotations of larger groups
1 parent c340e40 commit e5bda2d

File tree

1 file changed

+30
-7
lines changed

1 file changed

+30
-7
lines changed

kaitaistruct.py

+30-7
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818

1919
if PY2:
20+
range = xrange
2021
def integers2bytes(ints):
2122
return bytes(bytearray(ints))
2223
def bytes2integers(data):
@@ -363,15 +364,37 @@ def process_xor_many(data, key):
363364
return integers2bytes(a ^ b for a, b in zip(bytes2integers(data), itertools.cycle(bytes2integers(key))))
364365

365366
# formula taken from: http://stackoverflow.com/a/812039
366-
precomputed_rotations = {amount:[(i << amount) & 0xff | (i >> (-amount & 7)) for i in range(256)] for amount in range(8)}
367+
precomputed_single_rotations = {amount: [(i << amount) & 0xff | (i >> (8-amount)) for i in range(256)] for amount in range(1,8)}
367368

368369
@staticmethod
369370
def process_rotate_left(data, amount, group_size):
370-
if group_size != 1:
371-
raise Exception("unable to rotate groups other than 1 byte")
372-
amount = amount % 8
371+
amount = amount % (group_size * 8)
373372
if amount == 0:
374373
return data
375-
376-
translate = KaitaiStream.precomputed_rotations[amount]
377-
return integers2bytes(translate[a] for a in bytes2integers(data))
374+
data_ints = bytes2integers(data)
375+
376+
if group_size == 1:
377+
translate = KaitaiStream.precomputed_single_rotations[amount]
378+
return integers2bytes(translate[a] for a in data_ints)
379+
380+
if len(data) % group_size != 0:
381+
raise Exception("data length must be a multiple of group size")
382+
383+
if amount % 8 == 0:
384+
indices = [(i + amount//8) % group_size for i in range(group_size)]
385+
return integers2bytes(data_ints[i+k] for i in range(0,len(data),group_size) for k in indices)
386+
387+
amount1 = amount % 8
388+
amount2 = 8 - amount1
389+
indices_pairs = [ ((i+amount//8) % group_size, (i+1+amount//8) % group_size) for i in range(group_size)]
390+
return integers2bytes((data_ints[i+k1] << amount1) & 0xff | (data_ints[i+k2] >> amount2) for i in range(0,len(data),group_size) for k1,k2 in indices_pairs)
391+
392+
# NOTE: unused implementation, left for reference
393+
#
394+
# cap = (1 << 8 * group_size) - 1
395+
# anti_amount = -amount & (8 * group_size - 1)
396+
# for i in range(0,len(data),group_size):
397+
# group = bytes2combinedinteger(data[i:i+group_size])
398+
# group = (group << amount) & cap | (group >> anti_amount)
399+
# r.append(combinedinteger2bytes(group, group_size))
400+
# return b''.join(r)

0 commit comments

Comments
 (0)