07

07

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

2010.07.07(22:07)

Baseエンコーディング,Baseデコーディング用の、CppUnitテストケースです。

Base64Test.h

/********************************************************************
概要 : Base64Encode, Base64Decode のTestCaseクラス
*********************************************************************/

// for Leak Check
#include

#include
#include
#include
#include
USING_NAMESPACE_CPPUNIT

#include

/*
* Base64用TestCase
*/
class Base64Test : public TestCase
{
public:
explicit Base64Test(const char* name) : TestCase(name) {}

/// テストを初期化する。
virtual void setUp() {}

/// テストの後片付けをする。
virtual void tearDown() {}

/// テスト1。
void testFirst();

/// テスト2。
void testSecond();

/// 全てのテストの集合を返す。
static Test* suite();

private:
};



Base64Test.cpp

/********************************************************************
概要 : Base64Encode, Base64Decode のTestCaseクラス
*********************************************************************/

#include "Base64Test.h"
#include "Base64.h"

void Base64Test::testFirst() {
unsigned char in[32];
unsigned char out[32];
unsigned char ans[32];
size_t len = 0;

memcpy((char*)in,"A", sizeof(in));
memcpy((char*)ans,"QQ==", sizeof(ans));
TEST_ASSERT(Base64Encode(in,strlen((const char*)in),out,sizeof(out)) == strlen((const char*)ans));
printf("%s -> %s\n",in,out);
TEST_ASSERT(strncmp((const char*)out,(const char*)ans, sizeof(out)) == 0);

memcpy((char*)in,"AB", sizeof(in));
memcpy((char*)ans,"QUI=", sizeof(ans));
TEST_ASSERT(Base64Encode(in,strlen((const char*)in),out,sizeof(out)) == strlen((const char*)ans));
printf("%s -> %s\n",in,out);
TEST_ASSERT(strncmp((const char*)out,(const char*)ans, sizeof(out)) == 0);

memcpy((char*)in,"ABC", sizeof(in));
memcpy((char*)ans,"QUJD", sizeof(ans));
TEST_ASSERT(Base64Encode(in,strlen((const char*)in),out,sizeof(out)) == strlen((const char*)ans));
printf("%s -> %s\n",in,out);
TEST_ASSERT(strncmp((const char*)out,(const char*)ans, sizeof(out)) == 0);

memcpy((char*)in,"ABCD", sizeof(in));
memcpy((char*)ans,"QUJDRA==", sizeof(ans));
TEST_ASSERT(Base64Encode(in,strlen((const char*)in),out,sizeof(out)) == strlen((const char*)ans));
TEST_ASSERT(strncmp((const char*)out,(const char*)ans, sizeof(out)) == 0);

memcpy((char*)in,"ABCDE", sizeof(in));
memcpy((char*)ans,"QUJDREU=", sizeof(ans));
TEST_ASSERT(Base64Encode(in,strlen((const char*)in),out,sizeof(out)) == strlen((const char*)ans));
TEST_ASSERT(strncmp((const char*)out,(const char*)ans, sizeof(out)) == 0);

memcpy((char*)in,"ABCDEF", sizeof(in));
memcpy((char*)ans,"QUJDREVG", sizeof(ans));
TEST_ASSERT(Base64Encode(in,strlen((const char*)in),out,sizeof(out)) == strlen((const char*)ans));
TEST_ASSERT(strncmp((const char*)out,(const char*)ans, sizeof(out)) == 0);

memcpy((char*)in,"ABCDEFG", sizeof(in));
memcpy((char*)ans,"QUJDREVGRw==", sizeof(ans));
TEST_ASSERT(Base64Encode(in, strlen((const char*)in), out, sizeof(out)) == strlen((const char*)ans));
TEST_ASSERT(strncmp((const char*)out, (const char*)ans, sizeof(out)) == 0);

memcpy((char*)in,"\000", len = 1);
memcpy((char*)ans,"AA==", sizeof(ans));
TEST_ASSERT(Base64Encode(in, len, out, sizeof(out)) == strlen((const char*)ans));
TEST_ASSERT(strncmp((const char*)out, (const char*)ans, sizeof(out)) == 0);

memcpy((char*)in,"\000\001", len = 2);
memcpy((char*)ans,"AAE=", sizeof(ans));
TEST_ASSERT(Base64Encode(in, len, out, sizeof(out)) == strlen((const char*)ans));
TEST_ASSERT(strncmp((const char*)out, (const char*)ans, sizeof(out)) == 0);

memcpy((char*)in,"\000\001\002", len = 3);
memcpy((char*)ans,"AAEC", sizeof(ans));
TEST_ASSERT(Base64Encode(in, len, out, sizeof(out)) == strlen((const char*)ans));
TEST_ASSERT(strncmp((const char*)out, (const char*)ans, sizeof(out)) == 0);

memcpy((char*)in,"\000\001\002\003", len = 4);
memcpy((char*)ans,"AAECAw==", sizeof(ans));
TEST_ASSERT(Base64Encode(in, len, out, sizeof(out)) == strlen((const char*)ans));
TEST_ASSERT(strncmp((const char*)out, (const char*)ans, sizeof(out)) == 0);

memcpy((char*)in,"\000\001\002\003\004", len = 5);
memcpy((char*)ans,"AAECAwQ=", sizeof(ans));
TEST_ASSERT(Base64Encode(in, len, out, sizeof(out)) == strlen((const char*)ans));
TEST_ASSERT(strncmp((const char*)out, (const char*)ans, sizeof(out)) == 0);

memcpy((char*)in,"\000\001\002\003\004\005", len = 6);
memcpy((char*)ans,"AAECAwQF", sizeof(ans));
TEST_ASSERT(Base64Encode(in, len, out, sizeof(out)) == strlen((const char*)ans));
TEST_ASSERT(strncmp((const char*)out, (const char*)ans, sizeof(out)) == 0);

memcpy((char*)in,"\000\001\002\003\004\005\006", len = 7);
memcpy((char*)ans,"AAECAwQFBg==", sizeof(ans));
TEST_ASSERT(Base64Encode(in, len, out, sizeof(out)) == strlen((const char*)ans));
TEST_ASSERT(strncmp((const char*)out, (const char*)ans, sizeof(out)) == 0);

memcpy((char*)in,"\000abc\000", len = 5);
memcpy((char*)ans,"AGFiYwA=", sizeof(ans));
TEST_ASSERT(Base64Encode(in, len, out, sizeof(out)) == strlen((const char*)ans));
TEST_ASSERT(strncmp((const char*)out, (const char*)ans, sizeof(out)) == 0);

}

void Base64Test::testSecond() {
unsigned char in[32];
unsigned char out[32];
unsigned char ans[32];
size_t len = 0;

memcpy((char*)in,"QUJD", sizeof(ans));
memcpy((char*)ans,"ABC", sizeof(in));
printf("%d\n",Base64Decode(in,strlen((const char*)in),out,sizeof(out)));
printf("%s -> %s\n",in,out);
TEST_ASSERT(Base64Decode(in,strlen((const char*)in),out,sizeof(out)) == strlen((const char*)ans));
printf("%s -> %s\n",in,out);
TEST_ASSERT(strncmp((const char*)out,(const char*)ans, sizeof(out)) == 0);

memcpy((char*)in,"QUJDRA==", sizeof(ans));
memcpy((char*)ans,"ABCD", sizeof(in));
printf("%d\n",Base64Decode(in,strlen((const char*)in),out,sizeof(out)));
printf("%s -> %s\n",in,out);
TEST_ASSERT(Base64Decode(in,strlen((const char*)in),out,sizeof(out)) == strlen((const char*)ans));
printf("%s -> %s\n",in,out);
TEST_ASSERT(strncmp((const char*)out,(const char*)ans, sizeof(out)) == 0);

memcpy((char*)in,"QUJDREU=", sizeof(ans));
memcpy((char*)ans,"ABCDE", sizeof(in));
printf("%d\n",Base64Decode(in,strlen((const char*)in),out,sizeof(out)));
printf("%s -> %s\n",in,out);
TEST_ASSERT(Base64Decode(in,strlen((const char*)in),out,sizeof(out)) == strlen((const char*)ans));
printf("%s -> %s\n",in,out);
TEST_ASSERT(strncmp((const char*)out,(const char*)ans, sizeof(out)) == 0);

memcpy((char*)in,"QUJDREVG", sizeof(ans));
memcpy((char*)ans,"ABCDEF", sizeof(in));
TEST_ASSERT(Base64Decode(in,strlen((const char*)in),out,sizeof(out)) == strlen((const char*)ans));
printf("%s -> %s\n",in,out);
TEST_ASSERT(strncmp((const char*)out,(const char*)ans, sizeof(out)) == 0);
}

// template が使用できない環境ではこれを追加。
DECLARE_TEST_CALLER(Base64Test)

/**
* 全てのテストの集合を返す。
*/
Test* Base64Test::suite()
{
TestSuite* suite = new TestSuite("Base64Test");
suite->addTest(new TEST_CALLER(Base64Test, testFirst));
suite->addTest(new TEST_CALLER(Base64Test, testSecond));
return suite;
}


07

07

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

2010.07.07(21:51)

こちらは、Base64デコーディングの私の回答例です。

エンコーディングの場合は入力は8ビットバイナリですが、デコーディングの場合は、限られたASCIIコードを対象としなければならないため、処理を始めるまえに確認すべき事前条件がたくさんあります。

原則に反して1つの関数に出口がいっぱいある例ですが、こちらのほうが読みやすいと思います。

Base64.h

#ifndef samples_Base64_H
#define samples_Base64_H

typedef unsigned int size_t;
size_t Base64Encode(const unsigned char* in, size_t inLen, unsigned char* out, size_t outLen);
size_t Base64Decode(const unsigned char* in, size_t inLen, unsigned char* out, size_t outLen);

#endif



Base64.cpp (後半)

/********************************************************************
概要 : Base64デコーディング
関数 : size_t Base64Decode(const unsigned char* in, size_t inLen, unsigned char* out, size_t outLen)
引数 : in : 入力データの先頭ポインタ
inLen : 入力データサイズ
out : 出力バッファの先頭ポインタ
outLen : 出力バッファサイズ
戻り値 : 出力バッファに書き込んだデータサイズ

備考 :  
作成日 : 2010/06/29
作成者 : 島敏博       
*********************************************************************/

#include "Base64.h"

#define NULL ((void*)0)

static const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";


/*
* テーブルからインデックスを求める
*/
static int DecodeTable(unsigned char c)
{
for (int i = 0; i < 64; i++) {
if (table[i] == c) {
return i;
}
}
return (-1);
}

/*
* Base64デコーディング
* 4オクテット(6ビット*4=24ビット)の印字可能文字列から
* 3オクテット(8ビット*3=24ビット)のバイナリコードを作成する
*/
size_t Base64Decode(const unsigned char* in, size_t inLen, unsigned char* out, size_t outLen)
{
unsigned int ac24 = 0;
size_t readLen = inLen;
size_t writtenLen = 0;

/* 入力文字列、入力文字列長さ、出力バッファ、出力バッファサイズの確認 */
if (in == NULL || inLen == 0 || out == NULL || outLen == 0) {
return 0;
}
/* 入力文字列の長さは4の倍数でなければならない。*/
if ((inLen % 4) != 0) {
return 0;
}
/* '='を見つけたらその1つ前までを処理する */
for (size_t i = 0; i < inLen; i++) {
if (in[i] == '=') {
readLen = i;
break;
}
}
/* 処理すべき長さは2以上なければならない */
if (readLen < 2) {
return 0;
}
/* すべてテーブルに載っている文字でなければならない。*/
for (size_t i = 0; i < readLen; i++) {
if (DecodeTable(in[i]) < 0) {
return 0;
}
}
/* 処理すべき長さを3で割った端数を求める */
size_t remainLen = readLen % 4;
/* 端数は0,2または3でなければならない。*/
if (!(remainLen == 0 || remainLen == 2 || remainLen == 3)) {
return 0;
}
/* 出力バッファサイズを調べる */
if ((readLen / 4) * 3 + remainLen > outLen) {
return 0;
}

/* 4バイトずつのかたまりを処理する */
for (size_t i = 0; i < readLen / 4; i++) {
ac24 = DecodeTable(*in++);
ac24 <<= 6;
ac24 |= DecodeTable(*in++);
ac24 <<= 6;
ac24 |= DecodeTable(*in++);
ac24 <<= 6;
ac24 |= DecodeTable(*in++);
*out++ = (ac24 >> 16) & 0xff;
*out++ = (ac24 >> 8) & 0xff;
*out++ = (ac24) & 0xff;
writtenLen += 3;
}
/* 端数が2文字の場合 */
if (remainLen == 2) {
ac24 = DecodeTable(*in++);
ac24 <<= 6;
ac24 |= DecodeTable(*in++);
ac24 <<= 12;
*out++ = (ac24 >> 16) & 0xff;
writtenLen += 1;
}
/* 端数が3文字の場合 */
else if (remainLen == 3) {
ac24 = DecodeTable(*in++);
ac24 <<= 6;
ac24 |= DecodeTable(*in++);
ac24 <<= 6;
ac24 |= DecodeTable(*in++);
ac24 <<= 6;
*out++ = (ac24 >> 16) & 0xff;
*out++ = (ac24 >> 8) & 0xff;
writtenLen += 2;
}
*out = '\0';
return writtenLen;
}

06

29

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

2010.06.29(21:50)

私の解答例もあげておきます。

Base64.cpp (前半)


/********************************************************************
概要 : Base64エンコーディング
関数 : size_t Base64Encode(const unsigned char* in, size_t inLen, unsigned char* out, size_t outLen)
引数 : in : 入力データの先頭ポインタ
inLen : 入力データサイズ
out : 出力バッファの先頭ポインタ
outLen : 出力バッファサイズ
戻り値 : 出力バッファに書き込んだデータサイズ
作成日 : 2010/06/29
*********************************************************************/

#include "Base64.h"

#define NULL ((void*)0)

static const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

/*
* Base64エンコーディング
* 3オクテット(8ビット*3=24ビット)のバイナリコードをASCII文字のうちの
* 65文字([A-Za-z0-9+/]の64文字とパディングのための'=')だけを使用して
* 4オクテット(6ビット*4=24ビット)の印字可能文字列に変換する
*/
size_t Base64Encode(const unsigned char* in, size_t inLen, unsigned char* out, size_t outLen) //★10
{
unsigned int ac24 = 0;
size_t writtenLen = 0;
/* 入力文字数を 3で割った端数を求める。端数は0,1,2のいずれか */
size_t remainLen = inLen % 3;
size_t i = 0;

/* 入力文字列、入力文字列長さ、出力バッファ、出力バッファサイズの確認 */
if (in == NULL || inLen == 0 || out == NULL || outLen == 0) {
return 0; //★20
}
/* 出力バッファサイズが十分か調べる */
if ((inLen / 3 + 1) * 4 + 1 > outLen) {
return 0;
}
/* 3文字ずつ処理する */
for (i = 0; i < inLen / 3; i++) {
ac24 = *in++;
ac24 <<= 8;
ac24 |= *in++;
ac24 <<= 8;
ac24 |= *in++;
*out++ = table[(ac24 >> 18) & 0x3f];   //★30
*out++ = table[(ac24 >> 12) & 0x3f];
*out++ = table[(ac24 >> 6) & 0x3f];
*out++ = table[(ac24) & 0x3f];
writtenLen += 4;
}
/* 端数が1文字の場合 */
if (remainLen == 1) {
ac24 = *in++;
ac24 <<= 16;
*out++ = table[(ac24 >> 18) & 0x3f];
*out++ = table[(ac24 >> 12) & 0x3f];
*out++ = '=';
*out++ = '=';
writtenLen += 4;
}
/* 端数が2文字の場合 */
else if (remainLen == 2) {
ac24 = *in++;
ac24 <<= 8;
ac24 |= *in++;
ac24 <<= 8;
*out++ = table[(ac24 >> 18) & 0x3f];
*out++ = table[(ac24 >> 12) & 0x3f];
*out++ = table[(ac24 >> 6) & 0x3f];
*out++ = '=';
writtenLen += 4;
}
*out = '\0';
return writtenLen;
}



コメント
★10
引数の名前が、inとinLen、outとoutLenになっていて、前者が後者の部分文字列になっている。

★20
事前条件が不成立の場合はただちにreturn しており、出口が1つという原則に反している。
がこのほうが読みやすい。

★30
定数値がマクロ定義したものではなく直接値で書かれている。
がこのほうが読みやすい。

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;
}

06

29

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

2010.06.29(21:26)

まず最初の解答をもらいました。それに対してコメントをしました。


/**
* @file EncodeBase64.c
* @brief 文字列をBase64エンコードする。
* @par 2010.06.21 新規作成
*/

#include
#include "EncodeBase64.h"

/** 8bit/6bit文字用の単位 */ //★10
#define OCTET 8 //★20
#define SEXTET 6

/** 3個の8bit文字(合計24bit)が変換単位 */
#define OCTET_UNIT 3
/** 4個の6bit文字(合計24bit)が変換単位 */
#define SEXTET_UNIT 4

/** エンコード時の6bitマスク用 */
#define MASKING_SEXTET 0x00FC0000

/** 文字数埋めの文字 */
#define EQUAL '='

/** Base64文字の文字コード対応表 */
#define BASE64_TABLE_MAX 64
static 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 void EncodeUnit(unsigned int Temp, int Unit, char *Encoded);

/**
* 文字列をBase64形式にエンコードする
* @brief エンコード前文字列を、変換単位ずつBase64エンコードする。
* 結果は文字列用配列の中身に直接格納する。
* @param エンコード前文字列、エンコード後文字列を格納する配列のポインタ
* @return なし。
* @note OutString配列のサイズは、InStringの文字数の約1.5倍以上の長さが必要
*/
void EncodeBase64(char *InString, char *OutString) //★30 //★40
{
/** 変換する文字を変換単位ごとに一時記憶 */
unsigned int unUnitTemp = 0;

/** エンコードする文字数 */
int nToEncode = 0; //★50

/** 文字数÷変換単位の余り */
int nRemainder = 0;

/** 場合によって追加する空白文字 */
char cAddition = 0;

int i = 0;
char *cpInHead = NULL;
char *cpOutHead = NULL;

/** 先頭アドレス記憶 */
cpInHead = InString;
cpOutHead = OutString;

/** 文字数を数え上げる */
while (*InString != '\0') {
nToEncode++;
InString++;
}

/** 変換単位ずつ変換 */
for (i = 0; i < nToEncode; i++) { //★60
unUnitTemp |= cpInHead[i];
if ((i + 1) % OCTET_UNIT == 0) {
EncodeUnit(unUnitTemp, SEXTET_UNIT, OutString); //★70
OutString += SEXTET_UNIT;
}
unUnitTemp <<= OCTET;
}

/** 余りの処理 */
nRemainder = nToEncode % OCTET_UNIT;
if (nRemainder) {
/** 最後尾に空白文字を追加して変換 */
InString = &cAddition;
unUnitTemp <<= OCTET;
EncodeUnit(unUnitTemp, (nRemainder + 1), OutString); //★80
}

OutString = cpOutHead;

return;
}

/**
* 指定された文字数だけ文字列をBase64形式にエンコードする
* @brief 結果は文字列用配列の中身に直接格納する。
* @param エンコード前文字列、エンコードする文字数、エンコード後文字列を格納する配列のポインタ
* @return なし。
*/
void EncodeUnit(unsigned int String, int n, char *Encoded)
{

unsigned int unMaskBit = 0x00000000;
int nShiftBit = 0;
int i = 0;

for (i = 0; i < SEXTET_UNIT; i++) {
Encoded[i] = EQUAL; //★90
}
for (i = 0; i < n; i++) {
unMaskBit = MASKING_SEXTET >> (SEXTET * i); //★100
nShiftBit = SEXTET * (SEXTET_UNIT - (i + 1));
Encoded[i] = g_Base64Table[ ((String & unMaskBit) >> nShiftBit) ]; //★110
}
return;
}


指摘内容
★10
自分のCソースの中だけで使っている定数なので、EncodeBase64.hではなくて、cの中で定義しているのはたいへんよい。EncodeBase64.h のほうには外部に公開されている定義だけをいれるようにしよう。

★20
定数定義とテーブルの定義が先頭にあるのは原則通りだが、実際に使う部分がずっと後のほうなので、少し読みにくくなってしまった。

★30
関数での処理が失敗する可能性がある場合は、呼び出し側で成功不成功がわかるようにしよう。

★40
入力データの長さ、出力バッファのサイズも渡してもらおう。
そして、出力バッファの長さが不足する場合は処理を打ち切ること。

★50
(signed) int を使うところと、size_t を使うべきところと区別しよう。

★60
もし、入力データの長さが0だったら?

★70
関数を呼び出す側でどういう結果になるかわかっていたとしても、
関数の側で、何バイト書き込んだかを求めて返してもらい、それを足したほうが
安全で読みやすく、仕様変更にも強い。

★80
先のEncodeUnit 呼び出しとの違いがわかりにくい。
おそらく、この関数には2つの責務があるのだろう。

★90
nがSEXTET_UNITの場合は、この処理がまったく無駄になる。

★100
少し何をやっているのか読み取りにくい。
わかりやすく書き換えるか、コメントをつけるか。

★110
定数の定義や、g_Base64Tableの定義がかなり遠くにあるので、
正しいかどうか読むのが難しい。

プロフィール

島敏博

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リンクの表示