Search code examples
c++filebinaryfstream

Write a file bit by bit


Basically I'm tryng to read a file, change the last bit each 4 bit sequence, then read the changed file and revert it to the original. es test1.bin -> test2.bin -> test3.bin 00011100 -> 00001101 -> 00011100 However, while the second file is ok, the third one changes a bit every 8 instead of 4. This is the

int main(int argc, char** argv) {   
    ifstream f("C:\\Users\\simon\\Desktop\\test\\test.bin", ios::binary | ios::in);
    ofstream f_o("C:\\Users\\simon\\Desktop\\test\\test2.bin", ios::binary | ios::out);
    char c,app;

    int rund=0;
    while (f.get(c)){
        app=c;
        for (int i = 7; i >= 0; i--){
            if(rund==3){ //it's the 4th bit, I change it
                rund=0;
                if(((c >> i) & 1) == 0)  app |= 1 << i; //if it's 0 i change to 1
                else  app |= 0 << i;
                }   
            else  rund += 1;
        }
        f_o.put(app); 
    }

    f.close();
    f_o.close();

    ifstream f2("C:\\Users\\simon\\Desktop\\test\\test2.bin", ios::binary | ios::in);
    ofstream f_o2("C:\\Users\\simon\\Desktop\\test\\test3.bin", ios::binary | ios::out);

    rund=0;
    while (f2.get(c)){
        app=c;
        for (int i = 7; i >= 0; i--){ 
            if(rund==3){
                rund=0;
                if(((c >> i) & 1) == 0)  app |= 1 << i;
                else  app |= 0 << i;
                } 
            else  rund += 1;     
        }
        f_o2.put(app); 
    }

}

Solution

  • KIIV already effectively gave you the (incredibly-comparatively-simple) solution, so I'll just show it in action and explain why it works (I can't resist, the code reduction here is just too beautiful, and I'm not ashamed to admit that I have a love affair with xor.)

    New code:

    int main(int argc, char** argv) {   
        ifstream f("C:\\Users\\simon\\Desktop\\test\\test.bin", ios::binary | ios::in);
        ofstream f_o("C:\\Users\\simon\\Desktop\\test\\test2.bin", ios::binary | ios::out);
        char c;
    
        while (f.get(c))
            f_o.put(c ^ 0x11);
    
        f.close();
        f_o.close();
    
        ifstream f2("C:\\Users\\simon\\Desktop\\test\\test2.bin", ios::binary | ios::in);
        ofstream f_o2("C:\\Users\\simon\\Desktop\\test\\test3.bin", ios::binary | ios::out);
    
        while (f2.get(c))
            f_o2.put(c ^ 0x11);   
    }
    

    Bitwise Exclusive Or (XOR)

    The operator ^ performs a bitwise exclusive or, aka 'XOR' operation. It works on a bit-by-bit (bitwise!) basis as follows:

    0 ^ 0 -> 0
    0 ^ 1 -> 1
    1 ^ 0 -> 1
    1 ^ 1 -> 0
    

    In other words, A ^ B is 1 if one and only one of A, B are 1. Hence the 'exclusive' or.

    Bit Flipping with ^

    Xor is a singularly-interesting bitwise op. Other interesting properties aside, it's the perfect tool for when you need to 'flip' the state of a bit (that is, map a 1 to 0 or a 0 to 1).

    Suppose I take A ^ 1. If A is 0, then I have 0 ^ 1 = 1. If A is 1, then I have 1 ^ 1 = 0. So you see, if I xor a bit with 1, I effectively 'flip' the bit.

    OTOH, suppose I take A ^ 0. If A is 0, then I have 0 ^ 0 = 0. If A is 1, then I have 1 ^ 0 = 1. In other words, A ^ 0 = A!

    This is a perfect situation...we can construct a bitstring to xor with your byte, and each bit in that bitstring will determine whether or not the corresponding bit in your byte gets flipped!

    0x11

    The only remaining thing to understand is how to create the value needed to flip the bits you want. You want to flip the 4th and 8th bits. So we need to construct 00010001. If you know hex, it's immediately clear that this is 0x11. If not, use an online converter, and then go learn hexadecimal after you've finished this project..voila :)