expatのXML_SetUnknownEncodingHandlerとは。

そんなわけで、長い間(といっても一週間くらい)悩んでいたXML_SetUnknownEncodingHandlerの正体がわかりました。
結局、中のソースコードを追いかけて、どういう処理をしているかと調べないとわかりませんでした。

結論から先にいうと、expatはutf-8で出力するようにできていて、知らないエンコード→utf8をするのが、XML_SetUnknownEncodingHandlerらしいです。
出力の部分を変えれるのかまではわからんので、今のところ結論はそんな感じ。

cp932→UNICODE→utf-8という流れになっていて、これじゃあ、うちがやりたいこととはまるで真逆のことですぜ旦那って感じorz
cp932をそのまま出力したいから、エンコードをcp932にして、読み込んで、しらんエンコードだから、文字列の解釈はよろしく頼むぜだと思ったんですけどね。

ハンドラの中身。

static int convert(void* data, const char* s){    TExpat *expat = static_cast<texpat *>(data);    unsigned char lead = s[0];    if (_ismbblead(lead) == 0) {        //シングルバイト        return lead;    }    unsigned char trail = s[1];    int sjis =  (lead < < 8) | trail;    int unicode = expat->cp932.ConvertToUnicode(sjis);    //マルチバイト    return unicode;}int XMLCALL TExpat::UnknownEncodingCallback(void *handle_data, const XML_Char *name, XML_Encoding *info) {    TExpat *expat = static_cast</texpat><texpat *>(handle_data);    for (int i = 0; i < 128; i++) {        info->map[i] = i;    }    for (int i = 128; i < 256; i++) {        info->map[i] = -2;    }    info->convert = convert;    info->data = handle_data;    return XML_STATUS_OK;}

まずmapを設定するのですが、該当する文字コードが来たときにどうするかというのを設定します。
通常の数値は0x80までぽぽいとつっこんでしまって、いいとおもいます。
あと0x80以降は、エンコードで必要なバイト数をマイナスで突っ込むようです。

convertの中身がキモです。
多分シングルバイトの文字列はこないと思うのですが、一応チェックだけいれてます。
leadバイトとtrailバイトをあわせたコードがsjisになるので、それをUNICODEに変換します。

int unicode = expat->cp932.ConvertToUnicode(sjis);

まぁ、このコンバートするコードはうちが自前で作ったので、どう変換するかは任せます。
各自で用意してください。
んで、げっつしたunicodeの文字コードを返せば、convert関数の処理は終了です。

あとは、expatの方で勝手にutf8にして、XML_SetCharacterDataHandlerの第二引数に文字列ポインタを渡してくれます。

んあー。
わかったのはいいけど、しょんぼーりーだー。

さくさくsjisに変換してoutputするようにしちゃおう。
や、utf8のまま処理してもいいっちゃーいいんだけどー。

Leave a Comment


NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>