06

29

C言語プログラミング演習 解答1-2

2010.06.29(21:47)

解答1-1へのコメントをしたあと、それのアップデートを受け取りました。
コメントも増えて、だいぶわかりやすくなりました。


/**
* @file EncodeBase64.c
* @brief 文字列をBase64エンコードする。
* @par 2010.06.28
*/

#include
/** 8bit/6bit文字用の単位 */
#define OCTET 8
#define SEXTET 6
/** 一度に変換するbit数 */
#define CONVERT_BIT 24
/** 文字数埋めの文字 */
#define EQUAL '='
/** Base64文字の文字コード対応表 */
#define BASE64_TABLE_MAX 64
static const char g_Base64Table[BASE64_TABLE_MAX] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '+', '/'};

/** プロトタイプ宣言 */
static size_t EncodeUnit(unsigned int temp24Bit, size_t n, unsigned char *encoded) ;

/**
* 入力データをBase64形式にエンコードする
* @brief 入力データを、変換単位ずつBase64エンコードする。
* 結果は文字列用配列の中身に直接格納する。
* @param エンコード前データ、そのデータ長(単位:octet)
* エンコード後文字列を格納する配列のポインタ、その配列長
* @return エンコード成功時はエンコード後の文字数を返す。それ以外の場合は0を返す。
* @expect inLen = 0の場合は0を返す
*/
size_t EncodeBase64(const unsigned char *inData, size_t inLen, unsigned char *outData, size_t outLen)
{
/** 変換する文字を一時記憶(使用bit = 下位24bit) */
unsigned int temp24Bit = 0x00000000;
/** temp24Bitで使用しているbit数カウント */
int tempCount = 0;
size_t remainder = 0;
size_t i = 0;
size_t needLen = 0;
size_t encodedString = 0;
size_t encodedCount = 0;

/** 入力文字数は0より大きくなければならない */
if (inLen == 0) {
return encodedString;
}
/** 文字数制限値の計算(8bit文字が3つあるごとに6bit文字が4つできる)( +1 は終端文字用) */
needLen = ((inLen / 3) * 4) + 1;
/** 端数の計算(remainderの値は0か1か2となる) */
remainder = inLen % 3;
/** 端数がある場合、更に6bit文字が4つ必要 */
if(remainder > 0){
needLen += 4;
}
/** 文字数制限値以上の文字数でなければならない */
if (outLen < needLen) {
return encodedString;
}

/** 24bitずつ変換 */
for (i = 0; i < inLen; i++) {
temp24Bit |= inData[i];
tempCount += OCTET;
/** temp24Bitの下24bitにデータを貯めた場合 */
if (tempCount == CONVERT_BIT) {
tempCount = 0;
encodedCount = EncodeUnit(temp24Bit, 3, outData);
/** エンコードした文字数だけ、ポインタ移動と文字数カウントする */
outData += encodedCount;
encodedString += encodedCount;
}
temp24Bit <<= OCTET;
}

/** 端数の処理(remainderの値は0か1か2である) */
if (remainder > 0) {
/** 端数が1の場合はbit位置の調整をする */
/** 端数が2の場合はbit位置の調整は不要 */
if (remainder == 1) {
temp24Bit <<= OCTET;
}
/** 端数の文字をエンコードする(空白bitはシフトの際にできている) */
encodedCount = EncodeUnit(temp24Bit, remainder, outData);
outData += encodedCount;
encodedString += encodedCount;
/** 空き部分を'='で埋める */
for (i = 0; i < (4 - encodedCount); i++) {
*outData = EQUAL;
outData++;
encodedString++;
}
}
/** Base64は文字列なので終端文字追加 */
*outData = '\0';
return encodedString;
}

/**
* 指定したoctet数だけBase64形式にエンコードする
* @brief 引数の下位24bitを使用し、上位6bitずつ変換する。
* 変換するbit数が6bitの倍数でない場合は、空白bitを追加してあることが前提。
* 生成したBase64文字列は出力用配列に直接格納する。
* @param エンコード前データ、エンコードするoctet数、エンコード後文字列を格納する文字列のポインタ
* @return 生成されたBase64文字数(最大4)を返す
* @note nOctetの値は1か2か3である
*/
size_t EncodeUnit(unsigned int temp24Bit, size_t nOctet, unsigned char *encoded)
{
unsigned int maskBit = 0x0000003F;
int shiftBit = 18;
size_t encodedCount = 0;
size_t i = 0;
size_t nSextet = 0;
/**
* nOctetの値は1か2か3である
* nOctet == 1の場合、6bit文字を2つ作る(4bit余分に読み取る(8 + 4bit) )
* nOctet == 2の場合、6bit文字を3つ作る(2bit余分に読み取る(16 + 2bit) )
* nOctet == 3の場合、6bit文字を4つ作る(24bit)
*/
nSextet = nOctet + 1;

for (i = 0; i < nSextet; i++) {
/** 24bitの中から6bitずつマスクした値を元に、配列を参照する */
encoded[i] = g_Base64Table[ ((temp24Bit >> shiftBit) & maskBit) ];
encodedCount++;
shiftBit -= SEXTET;
}

return encodedCount;
}

コメントの投稿

非公開コメント

プロフィール

島敏博

Shima Toshihiro 島敏博
信州アルプスハイランド在住。HaskellとElixirが好き。組み込みソフトウェアアーキテクト、C++プログラマ、山歩き、美術館巡り、和食食べ歩き、日本赤十字社救急法指導員、インデックス投資、クラシック音楽、SESSAME会員、状態マシン設計、モデル駆動開発、ソフトウェアプロダクトライン、Rubyist、実践ビジネス英語

■ ツイッター
http://twitter.com/saltheads
■ Facebook
http://www.facebook.com/saltheads
■ Qiita
http://qiita.com/saltheads

印刷する場合は、ブラウザの印刷メニューではなく、このページの上から3cmくらいの青いところにある、「印刷」を押してみてください。少しうまく印刷できます。まだ完全ではないのですが、これで勘弁してください。


カテゴリ
最新記事
月別アーカイブ
最新コメント
検索フォーム
リンク
sessame
RSSリンクの表示