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

コメントの投稿

非公開コメント

プロフィール

島敏博

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