views:

180

answers:

4

I'm doing a steganography project where I read in bytes from a ppm file and add the least significant bit to an array. So once 8 bytes are read in, I would have 8 bits in my array, which should equal some character in a hidden message. Is there an easy way to convert an array of 0's and 1's into an ascii value? For example, the array: char bits[] = {0,1,1,1,0,1,0,0} would equal 't'. Plain C

Thanks for all the answers. I'm gonna give some of these a shot.

+4  A: 

A simple for loop would work - something like


    unsigned char ascii = 0;
    unsigned char i;

    for(i = 0; i < 8; i++)
       ascii |= (bits[7 - i] << i);

There might be a faster way to do this, but this is a start at least.

Sam Post
is there something missing in your for loop ?
stefanB
Had to fix some formatting, better now?
Sam Post
Yeah that was a mistake, thanks. bits contains '0' and '1', so I updated the loop.
Sam Post
@sam: bits is an array of 0's and 1's. Its not '0's and '1's
N 1.1
Are his bits 0 and 1 or are they '0' and '1'? His response to Gabe was that he meant the 'brackets' which I assume means the braces, so that would imply they are actual binary data rather than characters, no?
Jason Coco
Yes, I also meant braces : P it's been a long night. Just tried this code out and it worked, so thanks again stack overflow!
Nick
Ah, I missed his comment about the braces. Thanks. @Nick, glad to help and good luck!
Sam Post
+1 now since you updated.
N 1.1
+2  A: 

I wouldn't store the bits in an array -- I'd OR them with a char.

So you start off with a char value of 0: char bit = 0;

When you get the first bit, OR it with what you have: bit |= bit_just_read;

Keep doing that with each bit, shifting appropriately; i.e., after you get the next bit, do bit |= (next_bit << 1);. And so forth.

After you read your 8 bits, bit will be the appropriate ASCII value, and you can print it out or do whatever with it you want to do.

mipadi
His bits are in the other order. And you have to shift your power as well, otherwise, assuming next_bit is ever set, you just always end up with 0x2|bit_just_read
Jason Coco
I don't see the OP mention what order the bits are in, but yes, the algorithm I listed would have to be adjusted depending on the ordering; and yes, each step has to shift the value left by another bit.
mipadi
He made a pseudo assignment in his question. char bits[] = "0,1,1,1,0,1,0,0"; clearly the syntax is suspect but that is correct for 't', so...
Jason Coco
A: 

I agree with mipadi, don't bother storing in an array first, that's kind of pointless. Since you have to loop or otherwise keep track of the array index while reading it in, you might as well do it in one go. Something like this, perhaps?

bits = 0;

for ( i = 0; i < 8; ++i ) {
    lsb = get_byte_from_ppm_somehow() & 0x01;
    bits <<= 1 | lsb;
}
Duncan
A: 

As long as the bit endian is correct, this should work and compile down pretty small. If the bit endian is backwards then you should be able to change the initial value of mask to 1, the mask shift to <<= , and you might need to have (0x0ff & mask) as the do{}while conditional if your compiler doesn't do what it's supposed to with byte sized variables. Don't forget to do something for the magic functions that I included where I didn't know what you wanted or how you did something

#include <stdint.h> // needed for uint8_t
...
uint8_t acc, lsb, mask;
uint8_t buf[SOME_SIZE];
size_t len = 0;

while (is_there_more_ppm_data()) {
    acc = 0;
    mask = 0x80; // This is the high bit
    do {
         if (!is_there_more() ) {
             // I don't know what you think should happen if you run out  on a non-byte boundary
             EARLY_END_OF_DATA();
             break;
         }
         lsb = 1 & get_next_ppm_byte();
         acc |= lsb ? mask : 0; // You could use an if statement
         mask >>= 1;
    } while (mask);
    buf[len] = acc; // NOTE: I didn't worry about the running off the end of the buff, but you should. 
    len++;
}
nategoose