いろんなものはつながっている

バイナリファイルをASCII文字に変換しメールにはりつけて送ってみた

メールで添付ファイルを送付できない環境で作業することがある。

テキストメールは送れるので報告や自分にメールを送ってちょっとしたメモを残すことはできる。でも操作手順を残したりするのにどうしても画像などの添付ファイルで送りたいこともある。

そこでバイナリをテキストに変換してメールにはりつけて自分に送ってみてはどうだろうと考えた。もともとメールの添付ファイルもBase64などでエンコードされ英数字にして送付されるわけだからそれのマネごとをやってみた。

Base64では、バイナリ列を6ビットずつに分割し、6ビット列を英数字文字にマッピングしている()。

バイナリファイル1

今回、6と8(=1バイト)の最小公倍数の24ビット(=3バイト)ずつ読み込んでバイナリ列を6ビットずつに分割するようにした。

バイナリファイル2

Base64ではビット数が6の倍数になるように端数を0でうめているが、今回は24の倍数になるように端数を0でうめるようにした。つまり3バイトずつ読み込んで、例えば、最後が1バイトだけになった場合は2バイトを0でうめて3バイトになるようにした。

bool ReadFile()
{
    // 1バイト(=8ビット)ずつ読みこみ
    // 3バイト(=24ビット)よみこんだところで6ビットずつエンコード
    unsigned char szBitArray[BIT_ARRAY_SIZE];
    memset(szBitArray, '0', sizeof(szBitArray));
    szBitArray[BIT_ARRAY_SIZE - 1] = '\0';

    unsigned char szByte;
    int nByteNum = 0;
    while(fread(&szByte, sizeof(szByte), 1, m_fpIn) != 0){
        nByteNum++;
        int nIndex = ((nByteNum - 1) % 3) * 8;
        szBitArray[nIndex + 0] = (szByte & (0x80) ? '1' : '0');
        szBitArray[nIndex + 1] = (szByte & (0x40) ? '1' : '0');
        szBitArray[nIndex + 2] = (szByte & (0x20) ? '1' : '0');
        szBitArray[nIndex + 3] = (szByte & (0x10) ? '1' : '0');
        szBitArray[nIndex + 4] = (szByte & (0x08) ? '1' : '0');
        szBitArray[nIndex + 5] = (szByte & (0x04) ? '1' : '0');
        szBitArray[nIndex + 6] = (szByte & (0x02) ? '1' : '0');
        szBitArray[nIndex + 7] = (szByte & (0x01) ? '1' : '0');
        if(nByteNum % 3 == 0){
            //6bitずつエンコード
            EncodeEightToSix(szBitArray);
            //配列を全部0でうめる
            memset(szBitArray, '0', sizeof(szBitArray));
            szBitArray[BIT_ARRAY_SIZE - 1] = '\0';
        }
    }
    if(nByteNum % 3 != 0){
        EncodeEightToSix(szBitArray);
    }
}

bool EncodeEightToSix(unsigned char* szBitArray)
{
    int EncodedValue = 0;
    for(int i = 0; i < BIT_ARRAY_SIZE - 1; i++){
        int nPower = 5 - i % 6;
        EncodedValue += PowerOfTwo(nPower) * (szBitArray[i] - '0');
        if((i + 1) % 6 == 0){
            assert(EncodedValue < 64);
            fprintf(m_fpOut, "%c", ENCODED_CHAR[EncodedValue]);
            EncodedValue = 0;
        }
    }
    
    return true;
}

例えば、バイナリエディタで開くと
バイナリファイル3
と表現される画像バイナリファイル4をエンコードしてみると
/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAAiACYDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQID …
となる。

デコードは、英数字を変換表をもとに10進数の数値に変換し、それを2進数表現にする。エンコードと同じように24ビット(=6ビット x 4文字)ごとに処理をした。

bool ReadFile()
{
	unsigned char szBitArray[BIT_ARRAY_SIZE];
    memset(szBitArray, '0', sizeof(szBitArray));
    szBitArray[BIT_ARRAY_SIZE - 1] = '\0';

	int Buff;
	int nByteNum = 0;
	while ((Buff=fgetc(m_fpIn)) != EOF){
		nByteNum++;
		// 文字を数値に変換
		int nDecodedNum = DecodeMapping(Buff);
		// 10進数→2進数
		int nIndex = ((nByteNum - 1) % 4) * 6;
        szBitArray[nIndex + 0] = (nDecodedNum & (0x20) ? '1' : '0');
        szBitArray[nIndex + 1] = (nDecodedNum & (0x10) ? '1' : '0');
        szBitArray[nIndex + 2] = (nDecodedNum & (0x08) ? '1' : '0');
        szBitArray[nIndex + 3] = (nDecodedNum & (0x04) ? '1' : '0');
        szBitArray[nIndex + 4] = (nDecodedNum & (0x02) ? '1' : '0');
        szBitArray[nIndex + 5] = (nDecodedNum & (0x01) ? '1' : '0');

		// 24ビットたまったらビット列を書き込み
		if(nByteNum % 4 == 0){
			if(nByteNum == (m_FileSize - 2)) break;	
			DecodeSixToEight(szBitArray, 3);
            memset(szBitArray, '0', sizeof(szBitArray));
            szBitArray[BIT_ARRAY_SIZE - 1] = '\0';
		}
	}
	
	DecodeSixToEight(szBitArray, m_ExtraByteNum);
	//

    return true;
}

bool DecodeSixToEight(unsigned char* szBitArray, int nByte)
{
	for(int i = 0; i < nByte; i++){
		unsigned char Byte = 0;
		Byte += (szBitArray[i * 8 + 0] - '0') * 128;
		Byte += (szBitArray[i * 8 + 1] - '0') * 64;
		Byte += (szBitArray[i * 8 + 2] - '0') * 32;
		Byte += (szBitArray[i * 8 + 3] - '0') * 16;
		Byte += (szBitArray[i * 8 + 4] - '0') * 8;
		Byte += (szBitArray[i * 8 + 5] - '0') * 4;
		Byte += (szBitArray[i * 8 + 6] - '0') * 2;
		Byte += (szBitArray[i * 8 + 7] - '0') * 1;
		fwrite(&Byte, sizeof(unsigned char), 1, m_fpOut);
	}


	return true;
}

関連記事

コメント

  1. この記事へのコメントはありません。

  1. この記事へのトラックバックはありません。

スポンサード リンク

カテゴリー

スポンサード リンク