Archived

This topic is now archived and is closed to further replies.

BungoMan85

64bit encoding

Recommended Posts

im reading up on basic 64 bit encoding that is used in the MIME standard email message... thing.... whatever... anyways, what i need to know is how the following part of it is done.... (code wise, conceptualy its retardedly simple, but i cant seem to think of code that will do it) a file is taken 3 bytes at a time so that there is 24 bits, this is then broken into 4 6 bit numbers, each one representing an asci character (ive read this is to ensure that the file is easy to read no matter what it is being sent to). now the 64 bit part comes from 2^6=64... so thats kinda obvious... if the file size in bytes % 3 is not equal to zero then an appropriate number of 8bit ascii chars that equal the char ''0'' are appended... i guess basicly where im having trouble, is breaking the 3 8 bit numbers in the 4 6 bit numbers, argggg it messes with my head...
|===============================================|
|      155      |      162      |     233       |
|===============================================|
|1|0|0|1|1|0|1|1|1|0|1|0|0|0|1|0|1|1|1|0|1|0|0|1|
|===============================================|
|     38    |     58    |    11     |     41    |
|===============================================|
|    ''m''    |    ''6''    |    ''L''    |    ''p''    |
|===============================================|
 
thats pretty much how this website (http://email.about.com/library/weekly/aa070201a.htm) explained it. technicaly this would use more space since i cant have actual 6 bit chars, instead it takes the 6 bits and puts them into an 8 bit char, so what was 24 bits becomes 32. least thats my understanding (i may be way off). Bungo!

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
To convert the number to binary you can repeated divide them by 2. For example:

Quotient Remainder
135 / 2 67 1
67 / 2 33 1
33 / 2 16 1
16 / 2 8 0
8 / 2 4 0
4 / 2 2 0
2 / 2 1 0
1 / 2 0 1

the remainders from the binary equivlent. You have to read them from the bottom up.

10000111 = 135

Anyway store the binary representation in a string or character then parse your 4 6 bit numbers out of it and convert them back to digits. I sure one can find a more efficent way to do this, but this will get you started anyway.

Share this post


Link to post
Share on other sites
For your three bytes (b1, b2, b3), you need to convert them into 4 chars, taking 6 bits from the 24.

So for the first char, it''s the highest 6 bits of b1. Discard the lowest 2 bits.
c1 = b1 >> 2;

For the second, you want the highest 4 bits of b2 and the lowest 2 of b1.
c2 = (b2 >> 4) + ((b1 & 3) << 4);
Where did that 3 come from? 3 in binary is 00000011. Using the fact that x AND 1 = x, doing a boolean AND with b1 will ''evapourate'' all the bits apart from the ones that were high in the mask (our mask is 3, or 00000011). Then that value is shifted up 4 bits, to put it in the correct place.

And the third needs the highest 2 bits of b3 and the lowest 4 bits of b2:
c3 = (b3 >> 6) + ((b2 & 15) << 2);

And the fourth:
c4 = (b3 & 63);

Hope that helps,

--
Mr Smidge

Share this post


Link to post
Share on other sites
Converting binary numbers into a string, in order to convert them to binary again? Argh... Then, again, people keep pointing out that bit-shifting is a useless waste of time

Anyways, Smidge is right.

Edit: Just noticed that you wanted the other way round from what Smidge did, no?

Four bytes (b0,b1,b2,b3) into three bytes (b0,b1,b2), loosing the front to bits of each byte and ignoring b3 in the end.
(Counting bits starts with 0! Bit 0 is the first bit on the right of a byte)


b0 = b0 << 2 // get rid of b0's front two bits (6 & 7)

b0 = b0 | (b1 >> 4) & 0x03 // move bit 4 and 5 of b1 into b0

b1 = b1 << 4 // bit 3,2,1,0 of b1 remain

b1 = b1 | (b2 >> 2) & 0x0F // bit 4,5,3,2 of b2 into b1

b2 = b2 << 6 // bit 1,0 of b2 remain

b2 = b2 | (b3 >> 0) & 0x3F // bit 5,4,3,2,1,0 of b3 into b2


// 0-3: bits that used to be in b0-3

// x : undefined bits


1: b0 (0000 00xx) b1 (1111 1111) b2 (2222 2222) b3 (3333 3333)
2: b0 (0000 0011) b1 (1111 1111) b2 (2222 2222) b3 (3333 3333)
3: b0 (0000 0011) b1 (1111 xxxx) b2 (2222 2222) b3 (3333 3333)
4: b0 (0000 0011) b1 (1111 2222) b2 (2222 2222) b3 (3333 3333)
5: b0 (0000 0011) b1 (1111 2222) b2 (22xx xxxx) b3 (3333 3333)
6: b0 (0000 0011) b1 (1111 2222) b2 (2233 3333) b3 (3333 3333)


[edited by - Wildfire on July 3, 2003 10:52:47 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by Anonymous Poster
To convert the number to binary you can repeated divide them by 2. For example:

Quotient Remainder
135 / 2 67 1
67 / 2 33 1
33 / 2 16 1
16 / 2 8 0
8 / 2 4 0
4 / 2 2 0
2 / 2 1 0
1 / 2 0 1

the remainders from the binary equivlent. You have to read them from the bottom up.

10000111 = 135

Anyway store the binary representation in a string or character then parse your 4 6 bit numbers out of it and convert them back to digits. I sure one can find a more efficent way to do this, but this will get you started anyway.


Instead of using division you can use the itoa() function in cstdlib.

If you want to convert 135 it would look like this

int a = 135;
char buffer[8 * sizeof(a) + 1];

itoa(a,buffer,2);


where "a" is number you want to convert, the buffer is the location to store the output and 2 is the base.

Note the buffer size is = 8 * sizeof(int) + 1.

This is assumming you're using c++.




[edited by - prh99 on July 3, 2003 1:38:16 PM]

Share this post


Link to post
Share on other sites

#include <stdlib.h>
#include <fstream>
#include <string>

int base64encode(const std::string &file, std::string &buffer)
{
std::fstream infile(file.c_str(),std::ios::in|std::ios::binary);

if (!infile.is_open())
{
return 0;
}

buffer.resize(0);

char c;

while (true)
{
infile.get(c);
buffer.push_back(c)

if (infile.eof())
{
break;
}
}

switch (buffer.size()%3)
{
case 1: buffer.push_back("0");
break;
case 2: buffer.push_back("00");
break;
}

char temp1[4];
std::string temp2;

for (int counter=0;counter {
temp1[0]=buffer[counter]>>2;
temp1[1]=(buffer[counter+1]>>4)+((buffer[counter]&3<<4);
temp1[2]=(buffer[counter+2]>>6)+((buffer[counter+1]&15)<<2);
temp1[3]=buffer[counter+2]&63;

temp2.push_back(temp1);
}

buffer=temp2;

return buffer.size();
}

int base64decode(const std::string &file, std::string &buffer)
{
std::fstream infile(file.c_str(),std::ios::in|std::ios::binary);

if (!infile.is_open())
{
return 0;
}

buffer.resize(0);

char c;

while (true)
{
infile.get(c);
buffer.push_back(c)

if (infile.eof())
{
break;
}
}

char temp1[3];
std::string temp2;

for (int counter=0;counter {
temp1[0]=buffer[counter]<<2;
temp1[0]=buffer[counter]|(buffer[counter+1]>>4)&3;
temp1[1]=buffer[counter+1]<<4;
temp1[1]=buffer[counter+1]|(buffer[counter+2]>>2)&15;
temp1[2]=buffer[counter+2]<<6;
temp1[2]=buffer[counter+2]|(buffer[counter+3]>>0)&63;

temp2.push_back(temp1);
}

buffer=temp2;

return buffer.size();
}
[code]


thats what i got now =) thanks a ton for explaining it and explaining it well =). it actualy makes more sense, ive never been too good at binary math, doing simple stuff is easy, but taking parts of one number and logicaly putting it on another is something ive never had to do before (kind of an innacurate description, but you know what i mean).


Bungo!

Share this post


Link to post
Share on other sites