mcrblog

vcpp-ml

1999年08月

31

[vcpp 00032034] Re: Base64のDecode方法


 On 平 11 / 8 / 31 午後 10:43 
 Subject: [vcpp 00032033] Re: Base64の Decode方法
 In <1...@ha.bekkoame.ne.jp>
 vzy03312 = S.Yoshida writes:
vzy03312>
vzy03312>base64 エンコーディングは,0-63の数字を,

「数字」ではなくて「数値」というのが正しいのかな?

ではでは。 m(_ _;)m

-- 
S.Yoshida v...@ha.bekkoame.ne.jp
31

[vcpp 00032033] Re: Base64のDecode方法


 On 平 11 / 8 / 31 午後 9:08 
 Subject: [vcpp 00032031] Re: Base64の Decode方法
 In <1...@kded5.kde.daikin.co.jp>
 simatani = Keisuke SHIMATANI writes:
simatani>今晩は、嶋谷です。

遅くなりました。
今晩は,吉田です。

simatani>申し訳ないです。少し長くなりますが、MFC Programmer's Source Book の
simatani>CBase64 を掲載させていただきます。

ありがとうございます。


*BASE64について*

base64 エンコーディングは,0-63の数字を,

 大文字の A-Z, 小文字の a-z, 数字の0-9,+/
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

に割り当てて,バイナリファイルをアスキーへエンコーディングする方法です。
エンコードする一行が76文字となっています。うろ覚えですいませんが,76文字
で正しいのかどうかは,Encodeルーチンを参照して下さい。

simatani>// The size of the output buffer must not be less than
simatani>// 3/4 the size of the input buffer. For simplicity,
simatani>// make them the same size.

これは,以下のバイト数へデコードされるといった意味になります。

``ABCD"  -> (2^6)^4 = (2^8)^3 -> 3 bytes
``ABC="  -> 2 bytes
``AB=="  -> 1 bytes
 ``=" はパディングです。0とは意味的に異なります。
4の倍数にならない場合,base64エンコード時にパディングを使います。


*ふまえて,CBASE64について*

simatani> int nDecode[ 256 ];

nDecodeは,strchr(table, ch); では速度的に厳しいので変換
テーブルを持っているのでしょう。少なくとも,strchrよりも正
常に見えます。

simatani> ASSERT( szDecoding != NULL );
simatani> ASSERT( szOutput != NULL );

呼び出し元でメモリが足りない場合のチェックを怠っている等,
偶然 NULL ポインタになってしまっても,アクセス違反を起こ
さないコードになっていますね。

simatani> if( sInput.GetLength() == 0 )
simatani> return 0;

これは長さが0の行をスキップしています。

< SNIP >
simatani> nDecode[ m_sBase64Alphabet[ i ] ] = i;

テーブルの作成。

simatani> nDecode[ m_sBase64Alphabet[ i ] | 0x80 ] = i; // Ignore 8th bit

この部分は初めて知りました。

simatani> memset( szOutput, 0, sInput.GetLength() + 1 );

<後で説明>

simatani> if( nDigit < -1 ) 
simatani> {
simatani> return 0;

入力が正しく無い場合にはエラーとなるらしいですね。

simatani> else if( nDigit >= 0 ) 
simatani> // i (index into output) is incremented by write_bits()
simatani> write_bits( nDigit & 0x3F, 6, szOutput, i );

入力が正しい場合のみ,デコードしています。
write_bitsでは,カレントビット数をチェックしていますね。

simatani>行単位の処理の場合ですね。

CBase64では行単位でしか受け付けません。また,無関係な文字は受け付けま
せん。まっとうな方法ですが,支障がある場合もあるでしょう。ですが,
CStringの参照を引数にとったReadStringでは,"\r\n"を削除しますから,
なんら問題はありません。

*ふまえて,私の書いた利用方法のサンプルコードについて
  & 質問への私なりのお答え *

simatani>> CString    rcvbuf;  /* デコーダ出力 */
simatani>> CFile      output;  /* バイナリ出力 */
simatani>> int        b_len;
simatani>> char      *b_buf;

-- ここで入力ファイルと出力ファイルをオープンして下さい。

simatani>>   while( file.ReadString( &line ) ){
simatani>
simatani>ファイルの終わりまで達すると(戻り値NULLで)ループを抜けるのですね。

CStringを引数にとる,ReadStringでは,FALSEでファイルの終端になります。
NULLとは若干異なります。fgetsならばそうなのですけど。

EOFフラグを確認しても良いでしょう。
ファイルに,Ctrl+Z (0x1a)が含まれると,ファイルの終端として扱っている
様子なので,streamや,FileMapping,バイナリモードでの,peek, getcが必
要になる場合もあるかも知れません。今回のケースや,通常ではCStdioFileで
問題はありません。

simatani>GetLength() して、長さが0だったら再び制御式を評価するのですね。
simatani>break ではだめですか。

問題がなければそれでもいいです,
場合によっては,continue,
場合によっては,breakでは無いでしょうか?

CBase64の中でも,Length() == 0) return 0; としていますから,
if( b_len == 0 ) とした方が良いですね。なぜ,b_len == 0なのかを
チェックする手段が欲しいところですが。。
LOWORD,HIWORDで戻り値をマスクするのは格好が良くありませんので,
private:
   int m_errno; // 追加 Decode が return 0; の理由を調べる
public:
   int Fail() { return m_errno; }
としたいとも思います。

まぁ,普通はここまでする必要は無いのでしょう。

simatani>>     // Alloc 失敗のチェックを省略
simatani>>     b_buf = rcvbuf.GetBuffer( line.Length() );
simatani>
simatani>rcvbuf のバッファへポインタの取得ですか?
simatani>バッファのサイズもここで確保しているのですか?

バッファのサイズについては,memsetがありますので,line.Length() + 1
とする必要がありますね。

simatani>デコード結果が、b_buf に入るのですか?

そうです。返却値は,やはり,出力された長さであっています。

simatani>>     TRY {
simatani>
simatani>ここに、出力ファイルのオープンは、いりますか?

このループの一番そとです,前にオープンしています。

simatani>output.Close(); もいりますか?

これは最後です。

simatani>楽に済ませたいのですが、TRYを使えば何故楽になるのか分かりません。

int flag = 0;
if( !flag && !FuncA() ) flag = 1; // ファイルエラー
if( !flag && !FuncB() ) flag = 2; // メモリエラー
if( !flag && !FuncC() ) flag = 1; // ファイルエラー

if( flag ) { // エラーがおきました

といったコードを書く必要が無くなるのでは?と思っています。
親関数から呼び出した,子の関数の中のエラーをCATCHする事も可能です。

simatani>残念ながらソースを見ても分からないのです・・・。m(_ _)m

CBase64の場合には行単位(正しくは,意味的な単位ごと(パディング等,
正しい長さでエンコード・デコードを行える))に処理している様なので,
CStdioFileがやはり適当では無いでしょうか?

simatani>もう少しにらんでみます。

(^^;;
openの場所も分かりましたし,とりあえず実行して結果を見てはいかがで
せうか?

ではでは。

--- 
S.Yoshida v...@ha.bekkoame.ne.jp
31

[vcpp 00032032] Re: SDK でプロパティシートを実現するには?

T.Sawamoto 様

柏木泰幸です。
こんばんは。

答えてくれた皆様に非常に感謝しています。
プロパティページが中央に表示できました。

> PROPSHEETHEADERに指定するコールバックで初期化時を捉えられま
> すが、この時点ではいまだサイズが確定していないようなので中央
> に表示できませんね。
ずっとコールバック関数で色々してました。

ふるかわあきひとの
>| 実現できました。
>| でもこれを画面中央に表示したいのですがうまくできません。
>画面中央に出したことがないので…
>Parent WindowをDesktop Windowにしたらどうでしょうか。
ですが、できなかったです。

> 私のばやいはちと手抜き(^^;)をして、プロパティページ側の
> WM_INITDIALOGで親を取得し、移動してます。
> ただし、各ページは選択されないとWM_INITDIALOGが呼ばれませんの
> で、必ず最初に表示されるページに書いておく必要があります。
これを使って実現しました。
ほんっっっとに感謝しています。


> # MFCはフックして処理しているようですね。
そうなんですか。


でももう一つ困ったことがあります。
それは右上に表示される [?] が消えません。
PS?_HASHELP をはずしても消えません。
どうしてでしょうか?

どなたかお教え頂けないでしょうか?
よろしくお願いします。


..:*:・'゜☆。.:*:・'゜★。.:*:・'゜☆。.:*:・'゜
 Yasuyuki Kashiwagi
   mail: y...@d1.dion.ne.jp
..:*:・'゜★。.:*:・'゜☆。.:*:・'゜★。.:*:・'゜

※ホームページ『熊の家』は http://www.d1.dion.ne.jp/~yas_bear/ です。
31

[vcpp 00032031] Re: Base64のDecode方法

今晩は、嶋谷です。

すみません。せっかくサンプルコードまで書いていただいたのですが、
ちょっと私のレベルが低くてあまり理解できていません。
よろしければ、もう少し補足説明戴けないでしょうか?

At 19:13 99/08/31 +0900, S.Yoshida wrote:
>  shiumatani = Keisuke SHIMATANI writes:
> shiumatani># 使っている CBase64 は、行単位で処理するのだろうか???

> こちらは私は知りませんです。

申し訳ないです。少し長くなりますが、MFC Programmer's Source Book の
CBase64 を掲載させていただきます。
出典:
http://www.codeguru.com/xlate/japanese/

// The size of the output buffer must not be less than
// 3/4 the size of the input buffer. For simplicity,
// make them the same size.
int CBase64::Decode(LPCTSTR szDecoding, LPTSTR szOutput)
{
CString sInput;
int c, lp =0;
int nDigit;
int nDecode[ 256 ];

ASSERT( szDecoding != NULL );
ASSERT( szOutput != NULL );
if( szOutput == NULL )
return 0;
if( szDecoding == NULL )
return 0;
sInput = szDecoding;
if( sInput.GetLength() == 0 )
return 0;

// Build Decode Table
//
for( int i = 0; i < 256; i++ ) 
nDecode[i] = -2; // Illegal digit
for( i=0; i < 64; i++ )
{
nDecode[ m_sBase64Alphabet[ i ] ] = i;
nDecode[ m_sBase64Alphabet[ i ] | 0x80 ] = i; // Ignore 8th bit
nDecode[ '=' ] = -1; 
nDecode[ '=' | 0x80 ] = -1; // Ignore MIME padding char
}

// Clear the output buffer
memset( szOutput, 0, sInput.GetLength() + 1 );

// Decode the Input
//
for( lp = 0, i = 0; lp < sInput.GetLength(); lp++ )
{
c = sInput[ lp ];
nDigit = nDecode[ c & 0x7F ];
if( nDigit < -1 ) 
{
return 0;

else if( nDigit >= 0 ) 
// i (index into output) is incremented by write_bits()
write_bits( nDigit & 0x3F, 6, szOutput, i );
}
return i;
}


void CBase64::write_bits(UINT nBits,
 int nNumBits,
 LPTSTR szOutput,
 int& i)
{
UINT nScratch;

m_lBitStorage = (m_lBitStorage << nNumBits) | nBits;
m_nBitsRemaining += nNumBits;
while( m_nBitsRemaining > 7 ) 
{
nScratch = m_lBitStorage >> (m_nBitsRemaining - 8);
szOutput[ i++ ] = nScratch & 0xFF;
m_nBitsRemaining -= 8;
}
}

> CStdioFile::ReadString を使うと長さを調べる必要はありません。
> 今回は楽じゃないでしょうか?こんな感じ。

> CBase64    base64;  /* デコーダ     */
> CStdioFile file;    /* テキスト入力 */
> CString    line;    /* 行入力用     */

行単位の処理の場合ですね。

> CString    rcvbuf;  /* デコーダ出力 */
> CFile      output;  /* バイナリ出力 */
> int        b_len;
> char      *b_buf;

>   while( file.ReadString( &line ) ){

ファイルの終わりまで達すると(戻り値NULLで)ループを抜けるのですね。

>     if( line.Length() == 0 ){
>       continue;
>     }

GetLength() して、長さが0だったら再び制御式を評価するのですね。
break ではだめですか。

>     // Alloc 失敗のチェックを省略
>     b_buf = rcvbuf.GetBuffer( line.Length() );

rcvbuf のバッファへポインタの取得ですか?
バッファのサイズもここで確保しているのですか?

>     // 出力 bytes を返却されるものとして,,f(^^;
>     b_len = base64.Decode( (LPCTSTR)line, b_buf );

デコード結果が、b_buf に入るのですか?

>     TRY {

ここに、出力ファイルのオープンは、いりますか?

output.Open("output.bin", CFile::modeWrite | CFile::modeCreate);

>       output.Write( b_buf, b_len );

そして、ファイルに出力ですか?

>     }
>     CATCH( CFileException, e ) {
>       // WriteError
>     }
>     rcvbuf.ReleaseBuffer(); // 必要だろうか?

output.Close(); もいりますか?

>   }

> 二つのループをまとめれば,長さのチェックは不要になると思います。

読み出しと書き出しの二つのループのことですね?

> shiumatani>TRY、CATCH とやらもいるのでしょうか?

> 楽に済ませるならば必要でしょうね。 (^^;)

楽に済ませたいのですが、TRYを使えば何故楽になるのか分かりません。

> CBase64には,入力長を指定する手段は用意されていないのでしょうか?
> インスタンスがあるという事は,バッファリングも行うのでしょうか?
> 行単位で処理する(最低でも 4 bytes 単位)方法が無難なきがします。

> バッファリングしてくれるなら,ReadFileの戻り値が 入力バッファの
> サイズになるはずです。

残念ながらソースを見ても分からないのです・・・。m(_ _)m

> # 私はどのクラスライブラリも使わない方が安全な気がします。
> # 下で呼び出している fopen がちょっと。
> # ところで,stream は消えてしまったのでしょうか? > 皆さん

> とりあえず,CBase64を使用するなら,よくそのソースをご覧になる
> 事をお勧めします。(^^)

もう少しにらんでみます。
31

[vcpp 00032030] Re: ATL のBSTR型

こんばんわ。

 上杉さん、terukさん、しけぞーさん 早速のレスありがとうございます。

 福原@いまだ進展なし。。。T_Tです。

 terukさんから教えていただいた、

teruk> CString->BSTR
teruk>  CString::AllocSysString 
teruk> 
teruk> BSTR->CString
teruk>  AfxBSTR2CString

 ですが、この変換は、COMサーバで行わなければならないのでしょうか?

 また、afxpriv2.hをインクルードすると、コンパイル時に

c:\program files\microsoft visual studio\vc98\mfc\include\afxv_w32.h(14) :
fatal error C1189: #error :
 WINDOWS.H already included.  MFC apps must not #include <windows.h>

とエラーが出てしまいます。

#うー もう泣きが入ってる・・・


 よろしくお願いします。



                 -以上- 
記事検索
Amazon.co.jp
  • ライブドアブログ