2008年10月07日

UTF-8のデコード

 先日 UTF-8 のデコード処理を組み込む用事がありました。
 デコードの方法というか、定義自体は知っていたので、特に問題なく組み込めました。

 で、正しく認識しておこうと思い、資料を幾つか見てみるとイマイチ分かりにくい。
 それが個人的にちょっと気になったので、息抜きがてら少しまとめてみようと思います。


 UTF-8 の場合、ASCII 範囲の場合は 1 バイトで、それ以外は 2~6 バイトにエンコードされています。
 とはいえ、5~6 バイトは現時点では不正なコードと扱っても問題ないとされていますので、バッファオーバーフローさえしない作りにしておけば、とりあえずは問題ないでしょう。

 で、1バイトの場合はそのまま下位 7 ビットに当て嵌めれば問題ないのですが、少し面倒なのが 2~4 バイトの時。
 でもビットストリームを図解すると結構簡単です。

 ★1バイトの場合
  0aaa-aaaa

 ★2バイトの場合
  110a-aaaa 10bb-bbbb

 ★3バイトの場合
  1110-aaaa 10bb-bbbb 10cc-cccc

 ★4バイトの場合
  1111-0aaa 10bb-bbbb 10cc-cccc 10dd-dddd

 ★5バイトの場合
  1111-10aa 10bb-bbbb 10cc-cccc 10dd-dddd 10ee-eeee

 ★6バイトの場合
  1111-110a 10bb-bbbb 10cc-cccc 10dd-dddd 10ee-eeee 10ff-ffff

 0 と 1 はそのままの値が入って、バイト長の判定に使います。
 abcdef は、例えば a であれば、その文字の 1 バイト目でデータとして扱う部分。
 b であれば 2 バイト目の、c であれば 3 バイト目の……といった具合です。


 上のだとちょっと分かりにくいのですが、実際にデコードされたデータを並べると、以下のような感じ。

 ★1バイトの場合
  0000-0000 0000-0000 0aaa-aaaa (0x00007f ~ 0x000000)

 ★2バイトの場合
  0000-0000 0000-0aaa aabb-bbbb (0x0007ff ~ 0x000080)

 ★3バイトの場合
  0000-0000 aaaa-bbbb bbcc-cccc (0x00ffff ~ 0x000800)

 ★4バイトの場合
  000a-aabb bbbb-cccc ccdd-dddd (0x1fffff ~ 0x010000)

 1 バイト目だけが特殊で、2 バイト目以降は下位 6 ビットを引っ張ってきているだけです。

 ちなみに、4 バイトの場合だと、既に Unicode の範囲外のところまで表現できています。
 逆を返すとここまでで現時点で Unicode で定義されている内容を全て表現出来るということです。
 その為、5 バイト以上のものについては、不正なコードとして扱えるわけです。  


2008年02月15日

Navigate2を使ってPOSTで送信してみる

 IWebBrowser2Navigate2で、PostDataを使えばPOSTで送信できるのかなぁ、と思って適当にやってみたら、何故だかGETで送られてしまい、色々試してもダメ。
 そこでグーグル先生に聞いてみたところ、バイト列じゃないとダメーという記述が。
 面倒だったのですが、ちょいちょいと関数を一個追加したところ、POSTで送信できるようになりました。
 良かった良かった。

 で、この件、海外のサイトでは結構詳しく書いてあるのですが、日本語でそのままズバリ書いてあるサイトは見当たりませんでした。
 Cで組んでる場合のサンプルコードも見当たらなかったのですが、わりと悩んでいる方も多いような感じだったので、コードを置いておきます。

unsigned char IENavigate_PostData_Create(LPVARIANT vcPost, LPCTSTR vcData){

LPSAFEARRAY vtPsa;
LPSTR vtPost_Data;
unsigned int vtElems = lstrlen(vcData);

if(!vcPost)
return(0);

VariantInit(vcPost);

vtPsa = SafeArrayCreateVector(VT_UI1, 0, vtElems);
if(!vtPsa)
return(0);

SafeArrayAccessData(vtPsa, (LPVOID*)&vtPost_Data);
memcpy(vtPost_Data, vcData, vtElems);
SafeArrayUnaccessData(vtPsa);

V_VT(vcPost) = VT_ARRAY | VT_UI1;
V_ARRAY(vcPost) = vtPsa;

return(1);

}

void IENavigate_Post(char *vcpURL, char *vcpPost){

CComVariant vtUrl(vcpURL);
CComVariant vtHeader("Content-type: application/x-www-form-urlencoded\r\n");
CComVariant vtEmpty;
VARIANT vtPost = {0};

if(IENavigate_PostData_Create(&vtPost, vcpPost))
objIE->Navigate2(&vtUrl, &vtEmpty, &vtEmpty, &vtPost, &vtHeader);

}