Here's a quick Python3 skeleton for bit mapping:
#!/usr/bin/env python3 -B
# -*- coding: utf-8 -*-
from sys import stdin, stdout, stderr, argv, exit
def bytefilter(source, output, mapping, chunk=2097152):
while True:
try:
data = source.read(chunk)
except BlockingIOError:
return
if len(data) < 1:
return
output.write(data.translate(mapping))
def bitremap(byte, form):
result = 0
for i in range(0, 8):
dstbit = 7 - i
srcbit = int(form[i])
if (byte & (1 << srcbit)):
result |= 1 << dstbit
return result
if __name__ == '__main__':
if len(argv) != 4:
stderr.write("\n")
stderr.write("Usage: %s INPUTFILE OUTPUTFILE BITPATTERN\n" % argv[0])
stderr.write("\n")
stderr.write("For no translation, use bitpattern 76543210.\n")
stderr.write("\n")
exit(1)
if len(argv[3]) != 8 or len(argv[3].rstrip("01234567")) != 0:
stderr.write("%s: Invalid bit pattern.\n" % argv[0])
exit(1)
mapping = b''
for i in range(0, 256):
mapping += b'%c' % bitremap(i, argv[3])
try:
source = open(argv[1], mode='rb')
except FileNotFoundError:
stderr.write("%s: No such file.\n" % argv[1])
exit(1)
output = open(argv[2], mode='wb')
bytefilter(source, output, mapping)
Run it without parameters to see usage. Simply put, it takes an input filename, and output filename, and the 8-digit bit pattern to use.
Normal bit pattern is 76543210. If you wish to swap the second bit (bit 1) and fourth bit (bit 3), use 76541230.
Essentially, the third parameter tells how the bits in the input bytes are mapped to the output file bytes.
It does not stop you from doing silly things, like 77777701, which uses the highest bit in input bytes for all but the two lowest bits, and swaps those two lowest bits.
The way this Python program works, is by constructing a 256-byte lookup table. The bitremap() function transforms one numeric value using the form string; it is called once for each possible byte value, to construct the lookup table. The Python .translate() method does the lookup efficiently.