Back to index

php5  5.3.10
mbfilter.c
Go to the documentation of this file.
00001 /*
00002  * charset=UTF-8
00003  * vim600: encoding=utf-8
00004  */
00005 
00006 /*
00007  * "streamable kanji code filter and converter"
00008  *
00009  * Copyright (c) 1998,1999,2000,2001 HappySize, Inc. All rights reserved.
00010  *
00011  * This software is released under the GNU Lesser General Public License.
00012  * (Version 2.1, February 1999)
00013  * Please read the following detail of the licence (in japanese).
00014  *
00015  * ◆使用許諾条件◆
00016  *
00017  * このソフトウェアは株式会社ハッピーサイズによって開発されました。株式会社ハッ
00018  * ピーサイズは、著作権法および万国著作権条約の定めにより、このソフトウェアに関
00019  * するすべての権利を留保する権利を持ち、ここに行使します。株式会社ハッピーサイ
00020  * ズは以下に明記した条件に従って、このソフトウェアを使用する排他的ではない権利
00021  * をお客様に許諾します。何人たりとも、以下の条件に反してこのソフトウェアを使用
00022  * することはできません。
00023  *
00024  * このソフトウェアを「GNU Lesser General Public License (Version 2.1, February
00025  * 1999)」に示された条件で使用することを、全ての方に許諾します。「GNU Lesser
00026  * General Public License」を満たさない使用には、株式会社ハッピーサイズから書面
00027  * による許諾を得る必要があります。
00028  *
00029  * 「GNU Lesser General Public License」の全文は以下のウェブページから取得でき
00030  * ます。「GNU Lesser General Public License」とは、これまでLibrary General
00031  * Public Licenseと呼ばれていたものです。
00032  *     http://www.gnu.org/ --- GNUウェブサイト
00033  *     http://www.gnu.org/copyleft/lesser.html --- ライセンス文面
00034  * このライセンスの内容がわからない方、守れない方には使用を許諾しません。
00035  *
00036  * しかしながら、当社とGNUプロジェクトとの特定の関係を示唆または主張するもので
00037  * はありません。
00038  *
00039  * ◆保証内容◆
00040  *
00041  * このソフトウェアは、期待された動作・機能・性能を持つことを目標として設計され
00042  * 開発されていますが、これを保証するものではありません。このソフトウェアは「こ
00043  * のまま」の状態で提供されており、たとえばこのソフトウェアの有用性ないし特定の
00044  * 目的に合致することといった、何らかの保証内容が、明示されたり暗黙に示されてい
00045  * る場合であっても、その保証は無効です。このソフトウェアを使用した結果ないし使
00046  * 用しなかった結果によって、直接あるいは間接に受けた身体的な傷害、財産上の損害
00047  * 、データの損失あるいはその他の全ての損害については、その損害の可能性が使用者
00048  * 、当社あるいは第三者によって警告されていた場合であっても、当社はその損害の賠
00049  * 償および補填を行いません。この規定は他の全ての、書面上または書面に無い保証・
00050  * 契約・規定に優先します。
00051  *
00052  * ◆著作権者の連絡先および使用条件についての問い合わせ先◆
00053  *
00054  * 〒102-0073
00055  * 東京都千代田区九段北1-13-5日本地所第一ビル4F
00056  * 株式会社ハッピーサイズ
00057  * Phone: 03-3512-3655, Fax: 03-3512-3656
00058  * Email: sales@happysize.co.jp
00059  * Web: http://happysize.com/
00060  *
00061  * ◆著者◆
00062  *
00063  * 金本 茂 <sgk@happysize.co.jp>
00064  *
00065  * ◆履歴◆
00066  *
00067  * 1998/11/10 sgk implementation in C++
00068  * 1999/4/25  sgk Cで書きなおし。
00069  * 1999/4/26  sgk 入力フィルタを実装。漢字コードを推定しながらフィルタを追加。
00070  * 1999/6/??      Unicodeサポート。
00071  * 1999/6/22  sgk ライセンスをLGPLに変更。
00072  *
00073  */
00074 
00075 /* 
00076  * Unicode support
00077  *
00078  * Portions copyright (c) 1999,2000,2001 by the PHP3 internationalization team.
00079  * All rights reserved.
00080  *
00081  */
00082 
00083 
00084 #ifdef HAVE_CONFIG_H
00085 #include "config.h"
00086 #endif
00087 
00088 #include <stddef.h>
00089 
00090 #ifdef HAVE_STRING_H
00091 #include <string.h>
00092 #endif
00093 
00094 #ifdef HAVE_STRINGS_H
00095 #include <strings.h>
00096 #endif
00097 
00098 #ifdef HAVE_STDDEF_H
00099 #include <stddef.h>
00100 #endif
00101 
00102 #include "mbfilter.h"
00103 #include "mbfl_filter_output.h"
00104 #include "mbfilter_pass.h"
00105 #include "filters/mbfilter_tl_jisx0201_jisx0208.h"
00106 
00107 #include "eaw_table.h"
00108 
00109 /* hex character table "0123456789ABCDEF" */
00110 static char mbfl_hexchar_table[] = {
00111        0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46
00112 };
00113 
00114 
00115 
00116 /*
00117  * encoding filter
00118  */
00119 #define CK(statement)       do { if ((statement) < 0) return (-1); } while (0)
00120 
00121 
00122 /*
00123  *  buffering converter
00124  */
00125 mbfl_buffer_converter *
00126 mbfl_buffer_converter_new(
00127     enum mbfl_no_encoding from,
00128     enum mbfl_no_encoding to,
00129     int buf_initsz)
00130 {
00131        mbfl_buffer_converter *convd;
00132 
00133        /* allocate */
00134        convd = (mbfl_buffer_converter*)mbfl_malloc(sizeof (mbfl_buffer_converter));
00135        if (convd == NULL) {
00136               return NULL;
00137        }
00138 
00139        /* initialize */
00140        convd->from = mbfl_no2encoding(from);
00141        convd->to = mbfl_no2encoding(to);
00142        if (convd->from == NULL) {
00143               convd->from = &mbfl_encoding_pass;
00144        }
00145        if (convd->to == NULL) {
00146               convd->to = &mbfl_encoding_pass;
00147        }
00148 
00149        /* create convert filter */
00150        convd->filter1 = NULL;
00151        convd->filter2 = NULL;
00152        if (mbfl_convert_filter_get_vtbl(convd->from->no_encoding, convd->to->no_encoding) != NULL) {
00153               convd->filter1 = mbfl_convert_filter_new(convd->from->no_encoding, convd->to->no_encoding, mbfl_memory_device_output, NULL, &convd->device);
00154        } else {
00155               convd->filter2 = mbfl_convert_filter_new(mbfl_no_encoding_wchar, convd->to->no_encoding, mbfl_memory_device_output, NULL, &convd->device);
00156               if (convd->filter2 != NULL) {
00157                      convd->filter1 = mbfl_convert_filter_new(convd->from->no_encoding,
00158                                    mbfl_no_encoding_wchar,
00159                                    (int (*)(int, void*))convd->filter2->filter_function,
00160                                    (int (*)(void*))convd->filter2->filter_flush,
00161                                    convd->filter2);
00162                      if (convd->filter1 == NULL) {
00163                             mbfl_convert_filter_delete(convd->filter2);
00164                      }
00165               }
00166        }
00167        if (convd->filter1 == NULL) {
00168               return NULL;
00169        }
00170 
00171        mbfl_memory_device_init(&convd->device, buf_initsz, buf_initsz/4);
00172 
00173        return convd;
00174 }
00175 
00176 void
00177 mbfl_buffer_converter_delete(mbfl_buffer_converter *convd)
00178 {
00179        if (convd != NULL) {
00180               if (convd->filter1) {
00181                      mbfl_convert_filter_delete(convd->filter1);
00182               }
00183               if (convd->filter2) {
00184                      mbfl_convert_filter_delete(convd->filter2);
00185               }
00186               mbfl_memory_device_clear(&convd->device);
00187               mbfl_free((void*)convd);
00188        }
00189 }
00190 
00191 void
00192 mbfl_buffer_converter_reset(mbfl_buffer_converter *convd)
00193 {
00194        mbfl_memory_device_reset(&convd->device);
00195 }
00196 
00197 int
00198 mbfl_buffer_converter_illegal_mode(mbfl_buffer_converter *convd, int mode)
00199 {
00200        if (convd != NULL) {
00201               if (convd->filter2 != NULL) {
00202                      convd->filter2->illegal_mode = mode;
00203               } else if (convd->filter1 != NULL) {
00204                      convd->filter1->illegal_mode = mode;
00205               } else {
00206                      return 0;
00207               }
00208        }
00209 
00210        return 1;
00211 }
00212 
00213 int
00214 mbfl_buffer_converter_illegal_substchar(mbfl_buffer_converter *convd, int substchar)
00215 {
00216        if (convd != NULL) {
00217               if (convd->filter2 != NULL) {
00218                      convd->filter2->illegal_substchar = substchar;
00219               } else if (convd->filter1 != NULL) {
00220                      convd->filter1->illegal_substchar = substchar;
00221               } else {
00222                      return 0;
00223               }
00224        }
00225 
00226        return 1;
00227 }
00228 
00229 int
00230 mbfl_buffer_converter_strncat(mbfl_buffer_converter *convd, const unsigned char *p, int n)
00231 {
00232        mbfl_convert_filter *filter;
00233        int (*filter_function)(int c, mbfl_convert_filter *filter);
00234 
00235        if (convd != NULL && p != NULL) {
00236               filter = convd->filter1;
00237               if (filter != NULL) {
00238                      filter_function = filter->filter_function;
00239                      while (n > 0) {
00240                             if ((*filter_function)(*p++, filter) < 0) {
00241                                    break;
00242                             }
00243                             n--;
00244                      }
00245               }
00246        }
00247 
00248        return n;
00249 }
00250 
00251 int
00252 mbfl_buffer_converter_feed(mbfl_buffer_converter *convd, mbfl_string *string)
00253 {
00254        int n;
00255        unsigned char *p;
00256        mbfl_convert_filter *filter;
00257        int (*filter_function)(int c, mbfl_convert_filter *filter);
00258 
00259        if (convd == NULL || string == NULL) {
00260               return -1;
00261        }
00262        mbfl_memory_device_realloc(&convd->device, convd->device.pos + string->len, string->len/4);
00263        /* feed data */
00264        n = string->len;
00265        p = string->val;
00266        filter = convd->filter1;
00267        if (filter != NULL) {
00268               filter_function = filter->filter_function;
00269               while (n > 0) {
00270                      if ((*filter_function)(*p++, filter) < 0) {
00271                             return -1;
00272                      }
00273                      n--;
00274               }
00275        }
00276 
00277        return 0;
00278 }
00279 
00280 int
00281 mbfl_buffer_converter_flush(mbfl_buffer_converter *convd)
00282 {
00283        if (convd == NULL) {
00284               return -1;
00285        }
00286 
00287        if (convd->filter1 != NULL) {
00288               mbfl_convert_filter_flush(convd->filter1);
00289        }
00290        if (convd->filter2 != NULL) {
00291               mbfl_convert_filter_flush(convd->filter2);
00292        }
00293 
00294        return 0;
00295 }
00296 
00297 mbfl_string *
00298 mbfl_buffer_converter_getbuffer(mbfl_buffer_converter *convd, mbfl_string *result)
00299 {
00300        if (convd != NULL && result != NULL && convd->device.buffer != NULL) {
00301               result->no_encoding = convd->to->no_encoding;
00302               result->val = convd->device.buffer;
00303               result->len = convd->device.pos;
00304        } else {
00305               result = NULL;
00306        }
00307 
00308        return result;
00309 }
00310 
00311 mbfl_string *
00312 mbfl_buffer_converter_result(mbfl_buffer_converter *convd, mbfl_string *result)
00313 {
00314        if (convd == NULL || result == NULL) {
00315               return NULL;
00316        }
00317        result->no_encoding = convd->to->no_encoding;
00318        return mbfl_memory_device_result(&convd->device, result);
00319 }
00320 
00321 mbfl_string *
00322 mbfl_buffer_converter_feed_result(mbfl_buffer_converter *convd, mbfl_string *string, 
00323                               mbfl_string *result)
00324 {
00325        if (convd == NULL || string == NULL || result == NULL) {
00326               return NULL;
00327        }
00328        mbfl_buffer_converter_feed(convd, string);
00329        if (convd->filter1 != NULL) {
00330               mbfl_convert_filter_flush(convd->filter1);
00331        }
00332        if (convd->filter2 != NULL) {
00333               mbfl_convert_filter_flush(convd->filter2);
00334        }
00335        result->no_encoding = convd->to->no_encoding;
00336        return mbfl_memory_device_result(&convd->device, result);
00337 }
00338 
00339 int mbfl_buffer_illegalchars(mbfl_buffer_converter *convd)
00340 {
00341        int num_illegalchars = 0;
00342 
00343        if (convd == NULL) {
00344               return 0;
00345        }
00346 
00347        if (convd->filter1 != NULL) {
00348               num_illegalchars += convd->filter1->num_illegalchar;
00349        }
00350 
00351        if (convd->filter2 != NULL) {
00352               num_illegalchars += convd->filter2->num_illegalchar;
00353        }
00354 
00355        return (num_illegalchars);
00356 }
00357 
00358 /*
00359  * encoding detector
00360  */
00361 mbfl_encoding_detector *
00362 mbfl_encoding_detector_new(enum mbfl_no_encoding *elist, int elistsz, int strict)
00363 {
00364        mbfl_encoding_detector *identd;
00365 
00366        int i, num;
00367        mbfl_identify_filter *filter;
00368 
00369        if (elist == NULL || elistsz <= 0) {
00370               return NULL;
00371        }
00372 
00373        /* allocate */
00374        identd = (mbfl_encoding_detector*)mbfl_malloc(sizeof(mbfl_encoding_detector));
00375        if (identd == NULL) {
00376               return NULL;
00377        }
00378        identd->filter_list = (mbfl_identify_filter **)mbfl_calloc(elistsz, sizeof(mbfl_identify_filter *));
00379        if (identd->filter_list == NULL) {
00380               mbfl_free(identd);
00381               return NULL;
00382        }
00383 
00384        /* create filters */
00385        i = 0;
00386        num = 0;
00387        while (i < elistsz) {
00388               filter = mbfl_identify_filter_new(elist[i]);
00389               if (filter != NULL) {
00390                      identd->filter_list[num] = filter;
00391                      num++;
00392               }
00393               i++;
00394        }
00395        identd->filter_list_size = num;
00396 
00397        /* set strict flag */
00398        identd->strict = strict;
00399 
00400        return identd;
00401 }
00402 
00403 void
00404 mbfl_encoding_detector_delete(mbfl_encoding_detector *identd)
00405 {
00406        int i;
00407 
00408        if (identd != NULL) {
00409               if (identd->filter_list != NULL) {
00410                      i = identd->filter_list_size;
00411                      while (i > 0) {
00412                             i--;
00413                             mbfl_identify_filter_delete(identd->filter_list[i]);
00414                      }
00415                      mbfl_free((void *)identd->filter_list);
00416               }
00417               mbfl_free((void *)identd);
00418        }
00419 }
00420 
00421 int
00422 mbfl_encoding_detector_feed(mbfl_encoding_detector *identd, mbfl_string *string)
00423 {
00424        int i, n, num, bad, res;
00425        unsigned char *p;
00426        mbfl_identify_filter *filter;
00427 
00428        res = 0;
00429        /* feed data */
00430        if (identd != NULL && string != NULL && string->val != NULL) {
00431               num = identd->filter_list_size;
00432               n = string->len;
00433               p = string->val;
00434               bad = 0;
00435               while (n > 0) {
00436                      for (i = 0; i < num; i++) {
00437                             filter = identd->filter_list[i];
00438                             if (!filter->flag) {
00439                                    (*filter->filter_function)(*p, filter);
00440                                    if (filter->flag) {
00441                                           bad++;
00442                                    }
00443                             }
00444                      }
00445                      if ((num - 1) <= bad) {
00446                             res = 1;
00447                             break;
00448                      }
00449                      p++;
00450                      n--;
00451               }
00452        }
00453 
00454        return res;
00455 }
00456 
00457 enum mbfl_no_encoding mbfl_encoding_detector_judge(mbfl_encoding_detector *identd)
00458 {
00459        mbfl_identify_filter *filter;
00460        enum mbfl_no_encoding encoding;
00461        int n;
00462 
00463        /* judge */
00464        encoding = mbfl_no_encoding_invalid;
00465        if (identd != NULL) {
00466               n = identd->filter_list_size - 1;
00467               while (n >= 0) {
00468                      filter = identd->filter_list[n];
00469                      if (!filter->flag) {
00470                             if (!identd->strict || !filter->status) {
00471                                    encoding = filter->encoding->no_encoding;
00472                             }
00473                      }
00474                      n--;
00475               }
00476  
00477               /* fallback judge */
00478               if (encoding ==      mbfl_no_encoding_invalid) {
00479                      n = identd->filter_list_size - 1;
00480                      while (n >= 0) {
00481                             filter = identd->filter_list[n];
00482                             if (!filter->flag) {
00483                                    encoding = filter->encoding->no_encoding;
00484                             }
00485                             n--;
00486                      }
00487               }
00488        }
00489 
00490        return encoding;
00491 }
00492 
00493 
00494 /*
00495  * encoding converter
00496  */
00497 mbfl_string *
00498 mbfl_convert_encoding(
00499     mbfl_string *string,
00500     mbfl_string *result,
00501     enum mbfl_no_encoding toenc)
00502 {
00503        int n;
00504        unsigned char *p;
00505        const mbfl_encoding *encoding;
00506        mbfl_memory_device device;
00507        mbfl_convert_filter *filter1;
00508        mbfl_convert_filter *filter2;
00509 
00510        /* initialize */
00511        encoding = mbfl_no2encoding(toenc);
00512        if (encoding == NULL || string == NULL || result == NULL) {
00513               return NULL;
00514        }
00515 
00516        filter1 = NULL;
00517        filter2 = NULL;
00518        if (mbfl_convert_filter_get_vtbl(string->no_encoding, toenc) != NULL) {
00519               filter1 = mbfl_convert_filter_new(string->no_encoding, toenc, mbfl_memory_device_output, 0, &device);
00520        } else {
00521               filter2 = mbfl_convert_filter_new(mbfl_no_encoding_wchar, toenc, mbfl_memory_device_output, 0, &device);
00522               if (filter2 != NULL) {
00523                      filter1 = mbfl_convert_filter_new(string->no_encoding, mbfl_no_encoding_wchar, (int (*)(int, void*))filter2->filter_function, NULL, filter2);
00524                      if (filter1 == NULL) {
00525                             mbfl_convert_filter_delete(filter2);
00526                      }
00527               }
00528        }
00529        if (filter1 == NULL) {
00530               return NULL;
00531        }
00532 
00533        if (filter2 != NULL) {
00534               filter2->illegal_mode = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR;
00535               filter2->illegal_substchar = 0x3f;        /* '?' */
00536        }
00537 
00538        mbfl_memory_device_init(&device, string->len, (string->len >> 2) + 8);
00539 
00540        /* feed data */
00541        n = string->len;
00542        p = string->val;
00543        if (p != NULL) {
00544               while (n > 0) {
00545                      if ((*filter1->filter_function)(*p++, filter1) < 0) {
00546                             break;
00547                      }
00548                      n--;
00549               }
00550        }
00551 
00552        mbfl_convert_filter_flush(filter1);
00553        mbfl_convert_filter_delete(filter1);
00554        if (filter2 != NULL) {
00555               mbfl_convert_filter_flush(filter2);
00556               mbfl_convert_filter_delete(filter2);
00557        }
00558 
00559        return mbfl_memory_device_result(&device, result);
00560 }
00561 
00562 
00563 /*
00564  * identify encoding
00565  */
00566 const mbfl_encoding *
00567 mbfl_identify_encoding(mbfl_string *string, enum mbfl_no_encoding *elist, int elistsz, int strict)
00568 {
00569        int i, n, num, bad;
00570        unsigned char *p;
00571        mbfl_identify_filter *flist, *filter;
00572        const mbfl_encoding *encoding;
00573 
00574        /* flist is an array of mbfl_identify_filter instances */
00575        flist = (mbfl_identify_filter *)mbfl_calloc(elistsz, sizeof(mbfl_identify_filter));
00576        if (flist == NULL) {
00577               return NULL;
00578        }
00579 
00580        num = 0;
00581        if (elist != NULL) {
00582               for (i = 0; i < elistsz; i++) {
00583                      if (!mbfl_identify_filter_init(&flist[num], elist[i])) {
00584                             num++;
00585                      }
00586               }
00587        }
00588 
00589        /* feed data */
00590        n = string->len;
00591        p = string->val;
00592 
00593        if (p != NULL) {
00594               bad = 0;
00595               while (n > 0) {
00596                      for (i = 0; i < num; i++) {
00597                             filter = &flist[i];
00598                             if (!filter->flag) {
00599                                    (*filter->filter_function)(*p, filter);
00600                                    if (filter->flag) {
00601                                           bad++;
00602                                    }
00603                             }
00604                      }
00605                      if ((num - 1) <= bad && !strict) {
00606                             break;
00607                      }
00608                      p++;
00609                      n--;
00610               }
00611        }
00612 
00613        /* judge */
00614        encoding = NULL;
00615 
00616        for (i = 0; i < num; i++) {
00617               filter = &flist[i];
00618               if (!filter->flag) {
00619                      if (strict && filter->status) {
00620                             continue;
00621                      }
00622                      encoding = filter->encoding;
00623                      break;
00624               }
00625        }
00626 
00627        /* fall-back judge */
00628        if (!encoding) {
00629               for (i = 0; i < num; i++) {
00630                      filter = &flist[i];
00631                      if (!filter->flag && (!strict || !filter->status)) {
00632                             encoding = filter->encoding;
00633                             break;
00634                      }
00635               }
00636        }
00637  
00638        /* cleanup */
00639        /* dtors should be called in reverse order */
00640        i = num; while (--i >= 0) {
00641               mbfl_identify_filter_cleanup(&flist[i]);
00642        }
00643 
00644        mbfl_free((void *)flist);
00645 
00646        return encoding;
00647 }
00648 
00649 const char*
00650 mbfl_identify_encoding_name(mbfl_string *string, enum mbfl_no_encoding *elist, int elistsz, int strict)
00651 {
00652        const mbfl_encoding *encoding;
00653 
00654        encoding = mbfl_identify_encoding(string, elist, elistsz, strict);
00655        if (encoding != NULL &&
00656            encoding->no_encoding > mbfl_no_encoding_charset_min &&
00657            encoding->no_encoding < mbfl_no_encoding_charset_max) {
00658               return encoding->name;
00659        } else {
00660               return NULL;
00661        }
00662 }
00663 
00664 enum mbfl_no_encoding
00665 mbfl_identify_encoding_no(mbfl_string *string, enum mbfl_no_encoding *elist, int elistsz, int strict)
00666 {
00667        const mbfl_encoding *encoding;
00668 
00669        encoding = mbfl_identify_encoding(string, elist, elistsz, strict);
00670        if (encoding != NULL &&
00671            encoding->no_encoding > mbfl_no_encoding_charset_min &&
00672            encoding->no_encoding < mbfl_no_encoding_charset_max) {
00673               return encoding->no_encoding;
00674        } else {
00675               return mbfl_no_encoding_invalid;
00676        }
00677 }
00678 
00679 
00680 /*
00681  *  strlen
00682  */
00683 static int
00684 filter_count_output(int c, void *data)
00685 {
00686        (*(int *)data)++;
00687        return c;
00688 }
00689 
00690 int
00691 mbfl_strlen(mbfl_string *string)
00692 {
00693        int len, n, m, k;
00694        unsigned char *p;
00695        const unsigned char *mbtab;
00696        const mbfl_encoding *encoding;
00697 
00698        encoding = mbfl_no2encoding(string->no_encoding);
00699        if (encoding == NULL || string == NULL) {
00700               return -1;
00701        }
00702 
00703        len = 0;
00704        if (encoding->flag & MBFL_ENCTYPE_SBCS) {
00705               len = string->len;
00706        } else if (encoding->flag & (MBFL_ENCTYPE_WCS2BE | MBFL_ENCTYPE_WCS2LE)) {
00707               len = string->len/2;
00708        } else if (encoding->flag & (MBFL_ENCTYPE_WCS4BE | MBFL_ENCTYPE_WCS4LE)) {
00709               len = string->len/4;
00710        } else if (encoding->mblen_table != NULL) {
00711               mbtab = encoding->mblen_table;
00712               n = 0;
00713               p = string->val;
00714               k = string->len;
00715               /* count */
00716               if (p != NULL) {
00717                      while (n < k) {
00718                             m = mbtab[*p];
00719                             n += m;
00720                             p += m;
00721                             len++;
00722                      };
00723               }
00724        } else {
00725               /* wchar filter */
00726               mbfl_convert_filter *filter = mbfl_convert_filter_new(
00727                 string->no_encoding, 
00728                 mbfl_no_encoding_wchar,
00729                 filter_count_output, 0, &len);
00730               if (filter == NULL) {
00731                      return -1;
00732               }
00733               /* count */
00734               n = string->len;
00735               p = string->val;
00736               if (p != NULL) {
00737                      while (n > 0) {
00738                             (*filter->filter_function)(*p++, filter);
00739                             n--;
00740                      }
00741               }
00742               mbfl_convert_filter_delete(filter);
00743        }
00744 
00745        return len;
00746 }
00747 
00748  
00749 /*
00750  *  strpos
00751  */
00752 struct collector_strpos_data {
00753        mbfl_convert_filter *next_filter;
00754        mbfl_wchar_device needle;
00755        int needle_len;
00756        int start;
00757        int output;
00758        int found_pos;
00759        int needle_pos;
00760        int matched_pos;
00761 };
00762 
00763 static int
00764 collector_strpos(int c, void* data)
00765 {
00766        int *p, *h, *m, n;
00767        struct collector_strpos_data *pc = (struct collector_strpos_data*)data;
00768 
00769        if (pc->output >= pc->start) {
00770               if (c == (int)pc->needle.buffer[pc->needle_pos]) {
00771                      if (pc->needle_pos == 0) {
00772                             pc->found_pos = pc->output;               /* found position */
00773                      }
00774                      pc->needle_pos++;                                       /* needle pointer */
00775                      if (pc->needle_pos >= pc->needle_len) {
00776                             pc->matched_pos = pc->found_pos;   /* matched position */
00777                             pc->needle_pos--;
00778                             goto retry;
00779                      }
00780               } else if (pc->needle_pos != 0) {
00781 retry:
00782                      h = (int *)pc->needle.buffer;
00783                      h++;
00784                      for (;;) {
00785                             pc->found_pos++;
00786                             p = h;
00787                             m = (int *)pc->needle.buffer;
00788                             n = pc->needle_pos - 1;
00789                             while (n > 0 && *p == *m) {
00790                                    n--;
00791                                    p++;
00792                                    m++;
00793                             }
00794                             if (n <= 0) {
00795                                    if (*m != c) {
00796                                           pc->needle_pos = 0;
00797                                    }
00798                                    break;
00799                             } else {
00800                                    h++;
00801                                    pc->needle_pos--;
00802                             }
00803                      }
00804               }
00805        }
00806 
00807        pc->output++;
00808        return c;
00809 }
00810 
00811 /*
00812  *     oddlen
00813  */
00814 int 
00815 mbfl_oddlen(mbfl_string *string)
00816 {
00817        int len, n, m, k;
00818        unsigned char *p;
00819        const unsigned char *mbtab;
00820        const mbfl_encoding *encoding;
00821 
00822 
00823        if (string == NULL) {
00824               return -1;
00825        }
00826        encoding = mbfl_no2encoding(string->no_encoding);
00827        if (encoding == NULL) {
00828               return -1;
00829        }
00830 
00831        len = 0;
00832        if (encoding->flag & MBFL_ENCTYPE_SBCS) {
00833               return 0;
00834        } else if (encoding->flag & (MBFL_ENCTYPE_WCS2BE | MBFL_ENCTYPE_WCS2LE)) {
00835               return len % 2;
00836        } else if (encoding->flag & (MBFL_ENCTYPE_WCS4BE | MBFL_ENCTYPE_WCS4LE)) {
00837               return len % 4;
00838        } else if (encoding->mblen_table != NULL) {
00839               mbtab = encoding->mblen_table;
00840               n = 0;
00841               p = string->val;
00842               k = string->len;
00843               /* count */
00844               if (p != NULL) {
00845                      while (n < k) {
00846                             m = mbtab[*p];
00847                             n += m;
00848                             p += m;
00849                      };
00850               }
00851               return n-k;
00852        } else {
00853               /* how can i do ? */
00854               return 0;
00855        }
00856        /* NOT REACHED */
00857 }
00858 
00859 int
00860 mbfl_strpos(
00861     mbfl_string *haystack,
00862     mbfl_string *needle,
00863     int offset,
00864     int reverse)
00865 {
00866        int result;
00867        mbfl_string _haystack_u8, _needle_u8;
00868        const mbfl_string *haystack_u8, *needle_u8;
00869        const unsigned char *u8_tbl;
00870 
00871        if (haystack == NULL || haystack->val == NULL || needle == NULL || needle->val == NULL) {
00872               return -8;
00873        }
00874 
00875        {
00876               const mbfl_encoding *u8_enc;
00877               u8_enc = mbfl_no2encoding(mbfl_no_encoding_utf8);
00878               if (u8_enc == NULL || u8_enc->mblen_table == NULL) {
00879                      return -8;
00880               }
00881               u8_tbl = u8_enc->mblen_table;
00882        }
00883 
00884        if (haystack->no_encoding != mbfl_no_encoding_utf8) {
00885               mbfl_string_init(&_haystack_u8);
00886               haystack_u8 = mbfl_convert_encoding(haystack, &_haystack_u8, mbfl_no_encoding_utf8);
00887               if (haystack_u8 == NULL) {
00888                      result = -4;
00889                      goto out;
00890               }
00891        } else {
00892               haystack_u8 = haystack;
00893        }
00894 
00895        if (needle->no_encoding != mbfl_no_encoding_utf8) {
00896               mbfl_string_init(&_needle_u8);
00897               needle_u8 = mbfl_convert_encoding(needle, &_needle_u8, mbfl_no_encoding_utf8);
00898               if (needle_u8 == NULL) {
00899                      result = -4;
00900                      goto out;
00901               }
00902        } else {
00903               needle_u8 = needle;
00904        }
00905 
00906        if (needle_u8->len < 1) {
00907               result = -8;
00908               goto out;
00909        }
00910 
00911        result = -1;
00912        if (haystack_u8->len < needle_u8->len) {
00913               goto out;
00914        }
00915 
00916        if (!reverse) {
00917               unsigned int jtbl[1 << (sizeof(unsigned char) * 8)];
00918               unsigned int needle_u8_len = needle_u8->len;
00919               unsigned int i;
00920               const unsigned char *p, *q, *e;
00921               const unsigned char *haystack_u8_val = haystack_u8->val,
00922                                   *needle_u8_val = needle_u8->val;
00923               for (i = 0; i < sizeof(jtbl) / sizeof(*jtbl); ++i) {
00924                      jtbl[i] = needle_u8_len + 1;
00925               }
00926               for (i = 0; i < needle_u8_len - 1; ++i) {
00927                      jtbl[needle_u8_val[i]] = needle_u8_len - i;
00928               }
00929               e = haystack_u8_val + haystack_u8->len;
00930               p = haystack_u8_val;
00931               while (--offset >= 0) {
00932                      if (p >= e) {
00933                             result = -16;
00934                             goto out;
00935                      }
00936                      p += u8_tbl[*p];
00937               }
00938               p += needle_u8_len;
00939               if (p > e) {
00940                      goto out;
00941               }
00942               while (p <= e) {
00943                      const unsigned char *pv = p;
00944                      q = needle_u8_val + needle_u8_len;
00945                      for (;;) {
00946                             if (q == needle_u8_val) {
00947                                    result = 0;
00948                                    while (p > haystack_u8_val) {
00949                                           unsigned char c = *--p;
00950                                           if (c < 0x80) {
00951                                                  ++result;
00952                                           } else if ((c & 0xc0) != 0x80) {
00953                                                  ++result;
00954                                           }      
00955                                    }
00956                                    goto out;
00957                             }
00958                             if (*--q != *--p) {
00959                                    break;
00960                             }
00961                      }
00962                      p += jtbl[*p];
00963                      if (p <= pv) {
00964                             p = pv + 1;
00965                      }
00966               }
00967        } else {
00968               unsigned int jtbl[1 << (sizeof(unsigned char) * 8)];
00969               unsigned int needle_u8_len = needle_u8->len, needle_len = 0;
00970               unsigned int i;
00971               const unsigned char *p, *e, *q, *qe;
00972               const unsigned char *haystack_u8_val = haystack_u8->val,
00973                                   *needle_u8_val = needle_u8->val;
00974               for (i = 0; i < sizeof(jtbl) / sizeof(*jtbl); ++i) {
00975                      jtbl[i] = needle_u8_len;
00976               }
00977               for (i = needle_u8_len - 1; i > 0; --i) {
00978                      unsigned char c = needle_u8_val[i];
00979                      jtbl[c] = i;
00980                      if (c < 0x80) {
00981                             ++needle_len;
00982                      } else if ((c & 0xc0) != 0x80) {
00983                             ++needle_len;
00984                      }
00985               }
00986               {
00987                      unsigned char c = needle_u8_val[0];
00988                      if (c < 0x80) {
00989                             ++needle_len;
00990                      } else if ((c & 0xc0) != 0x80) {
00991                             ++needle_len;
00992                      }
00993               }
00994               e = haystack_u8_val;
00995               p = e + haystack_u8->len;
00996               qe = needle_u8_val + needle_u8_len;
00997               if (offset < 0) {
00998                      if (-offset > needle_len) {
00999                             offset += needle_len; 
01000                             while (offset < 0) {
01001                                    unsigned char c;
01002                                    if (p <= e) {
01003                                           result = -16;
01004                                           goto out;
01005                                    }
01006                                    c = *(--p);
01007                                    if (c < 0x80) {
01008                                           ++offset;
01009                                    } else if ((c & 0xc0) != 0x80) {
01010                                           ++offset;
01011                                    }
01012                             }
01013                      }
01014               } else {
01015                      const unsigned char *ee = haystack_u8_val + haystack_u8->len;
01016                      while (--offset >= 0) {
01017                             if (e >= ee) {
01018                                    result = -16;
01019                                    goto out;
01020                             }
01021                             e += u8_tbl[*e];
01022                      }
01023               }
01024               if (p < e + needle_u8_len) {
01025                      goto out;
01026               }
01027               p -= needle_u8_len;
01028               while (p >= e) {
01029                      const unsigned char *pv = p;
01030                      q = needle_u8_val;
01031                      for (;;) {
01032                             if (q == qe) {
01033                                    result = 0;
01034                                    p -= needle_u8_len;
01035                                    while (p > haystack_u8_val) {
01036                                           unsigned char c = *--p;
01037                                           if (c < 0x80) {
01038                                                  ++result;
01039                                           } else if ((c & 0xc0) != 0x80) {
01040                                                  ++result;
01041                                           }      
01042                                    }
01043                                    goto out;
01044                             }
01045                             if (*q != *p) {
01046                                    break;
01047                             }
01048                             ++p, ++q;
01049                      }
01050                      p -= jtbl[*p];
01051                      if (p >= pv) {
01052                             p = pv - 1;
01053                      }
01054               }
01055        }
01056 out:
01057        if (haystack_u8 == &_haystack_u8) {
01058               mbfl_string_clear(&_haystack_u8);
01059        }
01060        if (needle_u8 == &_needle_u8) {
01061               mbfl_string_clear(&_needle_u8);
01062        }
01063        return result;
01064 }
01065 
01066 /*
01067  *  substr_count
01068  */
01069 
01070 int
01071 mbfl_substr_count(
01072     mbfl_string *haystack,
01073     mbfl_string *needle
01074    )
01075 {
01076        int n, result = 0;
01077        unsigned char *p;
01078        mbfl_convert_filter *filter;
01079        struct collector_strpos_data pc;
01080 
01081        if (haystack == NULL || needle == NULL) {
01082               return -8;
01083        }
01084        /* needle is converted into wchar */
01085        mbfl_wchar_device_init(&pc.needle);
01086        filter = mbfl_convert_filter_new(
01087          needle->no_encoding,
01088          mbfl_no_encoding_wchar,
01089          mbfl_wchar_device_output, 0, &pc.needle);
01090        if (filter == NULL) {
01091               return -4;
01092        }
01093        p = needle->val;
01094        n = needle->len;
01095        if (p != NULL) {
01096               while (n > 0) {
01097                      if ((*filter->filter_function)(*p++, filter) < 0) {
01098                             break;
01099                      }
01100                      n--;
01101               }
01102        }
01103        mbfl_convert_filter_flush(filter);
01104        mbfl_convert_filter_delete(filter);
01105        pc.needle_len = pc.needle.pos;
01106        if (pc.needle.buffer == NULL) {
01107               return -4;
01108        }
01109        if (pc.needle_len <= 0) {
01110               mbfl_wchar_device_clear(&pc.needle);
01111               return -2;
01112        }
01113        /* initialize filter and collector data */
01114        filter = mbfl_convert_filter_new(
01115          haystack->no_encoding,
01116          mbfl_no_encoding_wchar,
01117          collector_strpos, 0, &pc);
01118        if (filter == NULL) {
01119               mbfl_wchar_device_clear(&pc.needle);
01120               return -4;
01121        }
01122        pc.start = 0;
01123        pc.output = 0;
01124        pc.needle_pos = 0;
01125        pc.found_pos = 0;
01126        pc.matched_pos = -1;
01127 
01128        /* feed data */
01129        p = haystack->val;
01130        n = haystack->len;
01131        if (p != NULL) {
01132               while (n > 0) {
01133                      if ((*filter->filter_function)(*p++, filter) < 0) {
01134                             pc.matched_pos = -4;
01135                             break;
01136                      }
01137                      if (pc.matched_pos >= 0) {
01138                             ++result;
01139                             pc.matched_pos = -1;
01140                             pc.needle_pos = 0;
01141                      }
01142                      n--;
01143               }
01144        }
01145        mbfl_convert_filter_flush(filter);
01146        mbfl_convert_filter_delete(filter);
01147        mbfl_wchar_device_clear(&pc.needle);
01148 
01149        return result;
01150 }
01151 
01152 /*
01153  *  substr
01154  */
01155 struct collector_substr_data {
01156        mbfl_convert_filter *next_filter;
01157        int start;
01158        int stop;
01159        int output;
01160 };
01161 
01162 static int
01163 collector_substr(int c, void* data)
01164 {
01165        struct collector_substr_data *pc = (struct collector_substr_data*)data;
01166 
01167        if (pc->output >= pc->stop) {
01168               return -1;
01169        }
01170 
01171        if (pc->output >= pc->start) {
01172               (*pc->next_filter->filter_function)(c, pc->next_filter);
01173        }
01174 
01175        pc->output++;
01176 
01177        return c;
01178 }
01179 
01180 mbfl_string *
01181 mbfl_substr(
01182     mbfl_string *string,
01183     mbfl_string *result,
01184     int from,
01185     int length)
01186 {
01187        const mbfl_encoding *encoding;
01188        int n, m, k, len, start, end;
01189        unsigned char *p, *w;
01190        const unsigned char *mbtab;
01191 
01192        encoding = mbfl_no2encoding(string->no_encoding);
01193        if (encoding == NULL || string == NULL || result == NULL) {
01194               return NULL;
01195        }
01196        mbfl_string_init(result);
01197        result->no_language = string->no_language;
01198        result->no_encoding = string->no_encoding;
01199 
01200        if ((encoding->flag & (MBFL_ENCTYPE_SBCS | MBFL_ENCTYPE_WCS2BE | MBFL_ENCTYPE_WCS2LE | MBFL_ENCTYPE_WCS4BE | MBFL_ENCTYPE_WCS4LE)) ||
01201           encoding->mblen_table != NULL) {
01202               len = string->len;
01203               start = from;
01204               end = from + length;
01205               if (encoding->flag & (MBFL_ENCTYPE_WCS2BE | MBFL_ENCTYPE_WCS2LE)) {
01206                      start *= 2;
01207                      end = start + length*2;
01208               } else if (encoding->flag & (MBFL_ENCTYPE_WCS4BE | MBFL_ENCTYPE_WCS4LE)) {
01209                      start *= 4;
01210                      end = start + length*4;
01211               } else if (encoding->mblen_table != NULL) {
01212                      mbtab = encoding->mblen_table;
01213                      start = 0;
01214                      end = 0;
01215                      n = 0;
01216                      k = 0;
01217                      p = string->val;
01218                      if (p != NULL) {
01219                             /* search start position */
01220                             while (k <= from) {
01221                                    start = n;
01222                                    if (n >= len) {
01223                                           break;
01224                                    }
01225                                    m = mbtab[*p];
01226                                    n += m;
01227                                    p += m;
01228                                    k++;
01229                             }
01230                             /* detect end position */
01231                             k = 0;
01232                             end = start;
01233                             while (k < length) {
01234                                    end = n;
01235                                    if (n >= len) {
01236                                           break;
01237                                    }
01238                                    m = mbtab[*p];
01239                                    n += m;
01240                                    p += m;
01241                                    k++;
01242                             }
01243                      }
01244               }
01245 
01246               if (start > len) {
01247                      start = len;
01248               }
01249               if (start < 0) {
01250                      start = 0;
01251               }
01252               if (end > len) {
01253                      end = len;
01254               }
01255               if (end < 0) {
01256                      end = 0;
01257               }
01258               if (start > end) {
01259                      start = end;
01260               }
01261 
01262               /* allocate memory and copy */
01263               n = end - start;
01264               result->len = 0;
01265               result->val = w = (unsigned char*)mbfl_malloc((n + 8)*sizeof(unsigned char));
01266               if (w != NULL) {
01267                      p = string->val;
01268                      if (p != NULL) {
01269                             p += start;
01270                             result->len = n;
01271                             while (n > 0) {
01272                                    *w++ = *p++;
01273                                    n--;
01274                             }
01275                      }
01276                      *w++ = '\0';
01277                      *w++ = '\0';
01278                      *w++ = '\0';
01279                      *w = '\0';
01280               } else {
01281                      result = NULL;
01282               }
01283        } else {
01284               mbfl_memory_device device;
01285               struct collector_substr_data pc;
01286               mbfl_convert_filter *decoder;
01287               mbfl_convert_filter *encoder;
01288 
01289               mbfl_memory_device_init(&device, length + 1, 0);
01290               mbfl_string_init(result);
01291               result->no_language = string->no_language;
01292               result->no_encoding = string->no_encoding;
01293               /* output code filter */
01294               decoder = mbfl_convert_filter_new(
01295                   mbfl_no_encoding_wchar,
01296                   string->no_encoding,
01297                   mbfl_memory_device_output, 0, &device);
01298               /* wchar filter */
01299               encoder = mbfl_convert_filter_new(
01300                   string->no_encoding,
01301                   mbfl_no_encoding_wchar,
01302                   collector_substr, 0, &pc);
01303               if (decoder == NULL || encoder == NULL) {
01304                      mbfl_convert_filter_delete(encoder);
01305                      mbfl_convert_filter_delete(decoder);
01306                      return NULL;
01307               }
01308               pc.next_filter = decoder;
01309               pc.start = from;
01310               pc.stop = from + length;
01311               pc.output = 0;
01312 
01313               /* feed data */
01314               p = string->val;
01315               n = string->len;
01316               if (p != NULL) {
01317                      while (n > 0) {
01318                             if ((*encoder->filter_function)(*p++, encoder) < 0) {
01319                                    break;
01320                             }
01321                             n--;
01322                      }
01323               }
01324 
01325               mbfl_convert_filter_flush(encoder);
01326               mbfl_convert_filter_flush(decoder);
01327               result = mbfl_memory_device_result(&device, result);
01328               mbfl_convert_filter_delete(encoder);
01329               mbfl_convert_filter_delete(decoder);
01330        }
01331 
01332        return result;
01333 }
01334 
01335 /*
01336  *  strcut
01337  */
01338 mbfl_string *
01339 mbfl_strcut(
01340     mbfl_string *string,
01341     mbfl_string *result,
01342     int from,
01343     int length)
01344 {
01345        const mbfl_encoding *encoding;
01346        mbfl_memory_device device;
01347 
01348        /* validate the parameters */
01349        if (string == NULL || string->val == NULL || result == NULL) {
01350               return NULL;
01351        }
01352 
01353        if (from < 0 || length < 0) {
01354               return NULL;
01355        }
01356 
01357        if (from >= string->len) {
01358               from = string->len;
01359        }
01360 
01361        encoding = mbfl_no2encoding(string->no_encoding);
01362        if (encoding == NULL) {
01363               return NULL;
01364        }
01365 
01366        mbfl_string_init(result);
01367        result->no_language = string->no_language;
01368        result->no_encoding = string->no_encoding;
01369 
01370        if ((encoding->flag & (MBFL_ENCTYPE_SBCS
01371                             | MBFL_ENCTYPE_WCS2BE
01372                             | MBFL_ENCTYPE_WCS2LE
01373                             | MBFL_ENCTYPE_WCS4BE
01374                             | MBFL_ENCTYPE_WCS4LE))
01375                      || encoding->mblen_table != NULL) {
01376               const unsigned char *start = NULL;
01377               const unsigned char *end = NULL;
01378               unsigned char *w;
01379               unsigned int sz;
01380 
01381               if (encoding->flag & (MBFL_ENCTYPE_WCS2BE | MBFL_ENCTYPE_WCS2LE)) {
01382                      from &= -2;
01383 
01384                      if (from + length >= string->len) {
01385                             length = string->len - from;
01386                      }
01387 
01388                      start = string->val + from;
01389                      end   = start + (length & -2);
01390               } else if (encoding->flag & (MBFL_ENCTYPE_WCS4BE | MBFL_ENCTYPE_WCS4LE)) {
01391                      from &= -4;
01392 
01393                      if (from + length >= string->len) {
01394                             length = string->len - from;
01395                      }
01396 
01397                      start = string->val + from;
01398                      end   = start + (length & -4);
01399               } else if ((encoding->flag & MBFL_ENCTYPE_SBCS)) {
01400                      if (from + length >= string->len) {
01401                             length = string->len - from;
01402                      }
01403 
01404                      start = string->val + from;
01405                      end = start + length;
01406               } else if (encoding->mblen_table != NULL) {
01407                      const unsigned char *mbtab = encoding->mblen_table;
01408                      const unsigned char *p, *q;
01409                      int m;
01410 
01411                      /* search start position */
01412                      for (m = 0, p = string->val, q = p + from;
01413                                    p < q; p += (m = mbtab[*p]));
01414 
01415                      if (p > q) {
01416                             p -= m;
01417                      }
01418 
01419                      start = p;
01420 
01421                      /* search end position */
01422                      if ((start - string->val) + length >= (int)string->len) {
01423                             end = string->val + string->len;
01424                      } else {
01425                             for (q = p + length; p < q; p += (m = mbtab[*p]));
01426 
01427                             if (p > q) {
01428                                    p -= m;
01429                             }
01430                             end = p;
01431                      }
01432               } else {
01433                      /* never reached */
01434                      return NULL;
01435               }
01436 
01437               /* allocate memory and copy string */
01438               sz = end - start;
01439               if ((w = (unsigned char*)mbfl_calloc(sz + 8,
01440                             sizeof(unsigned char))) == NULL) {
01441                      return NULL;
01442               }
01443 
01444               memcpy(w, start, sz);
01445               w[sz] = '\0';
01446               w[sz + 1] = '\0';
01447               w[sz + 2] = '\0';
01448               w[sz + 3] = '\0';
01449 
01450               result->val = w;
01451               result->len = sz;
01452        } else {
01453               mbfl_convert_filter *encoder     = NULL;
01454               mbfl_convert_filter *decoder     = NULL;
01455               const unsigned char *p, *q, *r;
01456               struct {
01457                      mbfl_convert_filter encoder;
01458                      mbfl_convert_filter decoder;
01459                      const unsigned char *p;
01460                      int pos;
01461               } bk, _bk;
01462 
01463               /* output code filter */
01464               if (!(decoder = mbfl_convert_filter_new(
01465                             mbfl_no_encoding_wchar,
01466                             string->no_encoding,
01467                             mbfl_memory_device_output, 0, &device))) {
01468                      return NULL;
01469               }
01470 
01471               /* wchar filter */
01472               if (!(encoder = mbfl_convert_filter_new(
01473                             string->no_encoding,
01474                             mbfl_no_encoding_wchar,
01475                             mbfl_filter_output_null,
01476                             NULL, NULL))) {
01477                      mbfl_convert_filter_delete(decoder);
01478                      return NULL;
01479               }
01480 
01481               mbfl_memory_device_init(&device, length + 8, 0);
01482 
01483               p = string->val;
01484 
01485               /* search start position */
01486               for (q = string->val + from; p < q; p++) {
01487                      (*encoder->filter_function)(*p, encoder);
01488               }
01489 
01490               /* switch the drain direction */
01491               encoder->output_function = (int(*)(int,void *))decoder->filter_function;
01492               encoder->flush_function = (int(*)(void *))decoder->filter_flush;
01493               encoder->data = decoder;
01494 
01495               q = string->val + string->len;
01496 
01497               /* save the encoder, decoder state and the pointer */
01498               mbfl_convert_filter_copy(decoder, &_bk.decoder);
01499               mbfl_convert_filter_copy(encoder, &_bk.encoder);
01500               _bk.p = p;
01501               _bk.pos = device.pos;
01502 
01503               if (length > q - p) {
01504                      length = q - p;
01505               }
01506 
01507               if (length >= 20) {
01508                      /* output a little shorter than "length" */
01509                      /* XXX: the constant "20" was determined purely on the heuristics. */
01510                      for (r = p + length - 20; p < r; p++) {
01511                             (*encoder->filter_function)(*p, encoder);
01512                      }
01513 
01514                      /* if the offset of the resulting string exceeds the length,
01515                       * then restore the state */
01516                      if (device.pos > length) {
01517                             p = _bk.p;
01518                             device.pos = _bk.pos;
01519                             decoder->filter_dtor(decoder);
01520                             encoder->filter_dtor(encoder);
01521                             mbfl_convert_filter_copy(&_bk.decoder, decoder);
01522                             mbfl_convert_filter_copy(&_bk.encoder, encoder);
01523                             bk = _bk;
01524                      } else {
01525                             /* save the encoder, decoder state and the pointer */
01526                             mbfl_convert_filter_copy(decoder, &bk.decoder);
01527                             mbfl_convert_filter_copy(encoder, &bk.encoder);
01528                             bk.p = p;
01529                             bk.pos = device.pos;
01530 
01531                             /* flush the stream */
01532                             (*encoder->filter_flush)(encoder);
01533 
01534                             /* if the offset of the resulting string exceeds the length,
01535                              * then restore the state */
01536                             if (device.pos > length) {
01537                                    bk.decoder.filter_dtor(&bk.decoder);
01538                                    bk.encoder.filter_dtor(&bk.encoder);
01539 
01540                                    p = _bk.p;
01541                                    device.pos = _bk.pos;
01542                                    decoder->filter_dtor(decoder);
01543                                    encoder->filter_dtor(encoder);
01544                                    mbfl_convert_filter_copy(&_bk.decoder, decoder);
01545                                    mbfl_convert_filter_copy(&_bk.encoder, encoder);
01546                                    bk = _bk;
01547                             } else {
01548                                    _bk.decoder.filter_dtor(&_bk.decoder);
01549                                    _bk.encoder.filter_dtor(&_bk.encoder);
01550 
01551                                    p = bk.p;
01552                                    device.pos = bk.pos;
01553                                    decoder->filter_dtor(decoder);
01554                                    encoder->filter_dtor(encoder);
01555                                    mbfl_convert_filter_copy(&bk.decoder, decoder);
01556                                    mbfl_convert_filter_copy(&bk.encoder, encoder);
01557                             }
01558                      }
01559               } else {
01560                      bk = _bk;
01561               }
01562 
01563               /* detect end position */
01564               while (p < q) {
01565                      (*encoder->filter_function)(*p, encoder);
01566 
01567                      if (device.pos > length) {
01568                             /* restore filter */
01569                             p = bk.p;
01570                             device.pos = bk.pos;
01571                             decoder->filter_dtor(decoder);
01572                             encoder->filter_dtor(encoder);
01573                             mbfl_convert_filter_copy(&bk.decoder, decoder);
01574                             mbfl_convert_filter_copy(&bk.encoder, encoder);
01575                             break;
01576                      }
01577 
01578                      p++;
01579 
01580                      /* backup current state */
01581                      mbfl_convert_filter_copy(decoder, &_bk.decoder);
01582                      mbfl_convert_filter_copy(encoder, &_bk.encoder);
01583                      _bk.pos = device.pos;
01584                      _bk.p = p;
01585 
01586                      (*encoder->filter_flush)(encoder);
01587 
01588                      if (device.pos > length) {
01589                             _bk.decoder.filter_dtor(&_bk.decoder);
01590                             _bk.encoder.filter_dtor(&_bk.encoder);
01591 
01592                             /* restore filter */
01593                             p = bk.p;
01594                             device.pos = bk.pos;
01595                             decoder->filter_dtor(decoder);
01596                             encoder->filter_dtor(encoder);
01597                             mbfl_convert_filter_copy(&bk.decoder, decoder);
01598                             mbfl_convert_filter_copy(&bk.encoder, encoder);
01599                             break;
01600                      }
01601 
01602                      bk.decoder.filter_dtor(&bk.decoder);
01603                      bk.encoder.filter_dtor(&bk.encoder);
01604 
01605                      p = _bk.p;
01606                      device.pos = _bk.pos;
01607                      decoder->filter_dtor(decoder);
01608                      encoder->filter_dtor(encoder);
01609                      mbfl_convert_filter_copy(&_bk.decoder, decoder);
01610                      mbfl_convert_filter_copy(&_bk.encoder, encoder);
01611 
01612                      bk = _bk;
01613               }
01614 
01615               (*encoder->filter_flush)(encoder);
01616 
01617               bk.decoder.filter_dtor(&bk.decoder);
01618               bk.encoder.filter_dtor(&bk.encoder);
01619 
01620               result = mbfl_memory_device_result(&device, result);
01621 
01622               mbfl_convert_filter_delete(encoder);
01623               mbfl_convert_filter_delete(decoder);
01624        }
01625 
01626        return result;
01627 }
01628 
01629 
01630 /*
01631  *  strwidth
01632  */
01633 static int is_fullwidth(int c)
01634 {
01635        int i;
01636 
01637        if (c < mbfl_eaw_table[0].begin) {
01638               return 0;
01639        }
01640 
01641        for (i = 0; i < sizeof(mbfl_eaw_table) / sizeof(mbfl_eaw_table[0]); i++) {
01642               if (mbfl_eaw_table[i].begin <= c && c <= mbfl_eaw_table[i].end) {
01643                      return 1;
01644               }
01645        }
01646 
01647        return 0;
01648 }
01649 
01650 static int
01651 filter_count_width(int c, void* data)
01652 {
01653        (*(int *)data) += (is_fullwidth(c) ? 2: 1);
01654        return c;
01655 }
01656 
01657 int
01658 mbfl_strwidth(mbfl_string *string)
01659 {
01660        int len, n;
01661        unsigned char *p;
01662        mbfl_convert_filter *filter;
01663 
01664        len = 0;
01665        if (string->len > 0 && string->val != NULL) {
01666               /* wchar filter */
01667               filter = mbfl_convert_filter_new(
01668                   string->no_encoding,
01669                   mbfl_no_encoding_wchar,
01670                   filter_count_width, 0, &len);
01671               if (filter == NULL) {
01672                      mbfl_convert_filter_delete(filter);
01673                      return -1;
01674               }
01675 
01676               /* feed data */
01677               p = string->val;
01678               n = string->len;
01679               while (n > 0) {
01680                      (*filter->filter_function)(*p++, filter);
01681                      n--;
01682               }
01683 
01684               mbfl_convert_filter_flush(filter);
01685               mbfl_convert_filter_delete(filter);
01686        }
01687 
01688        return len;
01689 }
01690 
01691 
01692 /*
01693  *  strimwidth
01694  */
01695 struct collector_strimwidth_data {
01696        mbfl_convert_filter *decoder;
01697        mbfl_convert_filter *decoder_backup;
01698        mbfl_memory_device device;
01699        int from;
01700        int width;
01701        int outwidth;
01702        int outchar;
01703        int status;
01704        int endpos;
01705 };
01706 
01707 static int
01708 collector_strimwidth(int c, void* data)
01709 {
01710        struct collector_strimwidth_data *pc = (struct collector_strimwidth_data*)data;
01711 
01712        switch (pc->status) {
01713        case 10:
01714               (*pc->decoder->filter_function)(c, pc->decoder);
01715               break;
01716        default:
01717               if (pc->outchar >= pc->from) {
01718                      pc->outwidth += (is_fullwidth(c) ? 2: 1);
01719 
01720                      if (pc->outwidth > pc->width) {
01721                             if (pc->status == 0) {
01722                                    pc->endpos = pc->device.pos;
01723                                    mbfl_convert_filter_copy(pc->decoder, pc->decoder_backup);
01724                             }
01725                             pc->status++;
01726                             (*pc->decoder->filter_function)(c, pc->decoder);
01727                             c = -1;
01728                      } else {
01729                             (*pc->decoder->filter_function)(c, pc->decoder);
01730                      }
01731               }
01732               pc->outchar++;
01733               break;
01734        }
01735 
01736        return c;
01737 }
01738 
01739 mbfl_string *
01740 mbfl_strimwidth(
01741     mbfl_string *string,
01742     mbfl_string *marker,
01743     mbfl_string *result,
01744     int from,
01745     int width)
01746 {
01747        struct collector_strimwidth_data pc;
01748        mbfl_convert_filter *encoder;
01749        int n, mkwidth;
01750        unsigned char *p;
01751 
01752        if (string == NULL || result == NULL) {
01753               return NULL;
01754        }
01755        mbfl_string_init(result);
01756        result->no_language = string->no_language;
01757        result->no_encoding = string->no_encoding;
01758        mbfl_memory_device_init(&pc.device, width, 0);
01759 
01760        /* output code filter */
01761        pc.decoder = mbfl_convert_filter_new(
01762            mbfl_no_encoding_wchar,
01763            string->no_encoding,
01764            mbfl_memory_device_output, 0, &pc.device);
01765        pc.decoder_backup = mbfl_convert_filter_new(
01766            mbfl_no_encoding_wchar,
01767            string->no_encoding,
01768            mbfl_memory_device_output, 0, &pc.device);
01769        /* wchar filter */
01770        encoder = mbfl_convert_filter_new(
01771            string->no_encoding,
01772            mbfl_no_encoding_wchar,
01773            collector_strimwidth, 0, &pc);
01774        if (pc.decoder == NULL || pc.decoder_backup == NULL || encoder == NULL) {
01775               mbfl_convert_filter_delete(encoder);
01776               mbfl_convert_filter_delete(pc.decoder);
01777               mbfl_convert_filter_delete(pc.decoder_backup);
01778               return NULL;
01779        }
01780        mkwidth = 0;
01781        if (marker) {
01782               mkwidth = mbfl_strwidth(marker);
01783        }
01784        pc.from = from;
01785        pc.width = width - mkwidth;
01786        pc.outwidth = 0;
01787        pc.outchar = 0;
01788        pc.status = 0;
01789        pc.endpos = 0;
01790 
01791        /* feed data */
01792        p = string->val;
01793        n = string->len;
01794        if (p != NULL) {
01795               while (n > 0) {
01796                      n--;
01797                      if ((*encoder->filter_function)(*p++, encoder) < 0) {
01798                             break;
01799                      }
01800               }
01801               mbfl_convert_filter_flush(encoder);
01802               if (pc.status != 0 && mkwidth > 0) {
01803                      pc.width += mkwidth;
01804                      while (n > 0) {
01805                             if ((*encoder->filter_function)(*p++, encoder) < 0) {
01806                                    break;
01807                             }
01808                             n--;
01809                      }
01810                      mbfl_convert_filter_flush(encoder);
01811                      if (pc.status != 1) {
01812                             pc.status = 10;
01813                             pc.device.pos = pc.endpos;
01814                             mbfl_convert_filter_copy(pc.decoder_backup, pc.decoder);
01815                             mbfl_convert_filter_reset(encoder, marker->no_encoding, mbfl_no_encoding_wchar);
01816                             p = marker->val;
01817                             n = marker->len;
01818                             while (n > 0) {
01819                                    if ((*encoder->filter_function)(*p++, encoder) < 0) {
01820                                           break;
01821                                    }
01822                                    n--;
01823                             }
01824                             mbfl_convert_filter_flush(encoder);
01825                      }
01826               } else if (pc.status != 0) {
01827                      pc.device.pos = pc.endpos;
01828                      mbfl_convert_filter_copy(pc.decoder_backup, pc.decoder);
01829               }
01830               mbfl_convert_filter_flush(pc.decoder);
01831        }
01832        result = mbfl_memory_device_result(&pc.device, result);
01833        mbfl_convert_filter_delete(encoder);
01834        mbfl_convert_filter_delete(pc.decoder);
01835        mbfl_convert_filter_delete(pc.decoder_backup);
01836 
01837        return result;
01838 }
01839 
01840 mbfl_string *
01841 mbfl_ja_jp_hantozen(
01842     mbfl_string *string,
01843     mbfl_string *result,
01844     int mode)
01845 {
01846        int n;
01847        unsigned char *p;
01848        const mbfl_encoding *encoding;
01849        mbfl_memory_device device;
01850        mbfl_convert_filter *decoder = NULL;
01851        mbfl_convert_filter *encoder = NULL;
01852        mbfl_convert_filter *tl_filter = NULL;
01853        mbfl_convert_filter *next_filter = NULL;
01854        mbfl_filt_tl_jisx0201_jisx0208_param *param = NULL;
01855 
01856        /* validate parameters */
01857        if (string == NULL || result == NULL) {
01858               return NULL;
01859        }
01860 
01861        encoding = mbfl_no2encoding(string->no_encoding);
01862        if (encoding == NULL) {
01863               return NULL;
01864        }
01865 
01866        mbfl_memory_device_init(&device, string->len, 0);
01867        mbfl_string_init(result);
01868 
01869        result->no_language = string->no_language;
01870        result->no_encoding = string->no_encoding;
01871 
01872        decoder = mbfl_convert_filter_new(
01873               mbfl_no_encoding_wchar,
01874               string->no_encoding,
01875               mbfl_memory_device_output, 0, &device);
01876        if (decoder == NULL) {
01877               goto out;
01878        }
01879        next_filter = decoder;
01880 
01881        param =
01882               (mbfl_filt_tl_jisx0201_jisx0208_param *)mbfl_malloc(sizeof(mbfl_filt_tl_jisx0201_jisx0208_param));
01883        if (param == NULL) {
01884               goto out;
01885        }
01886 
01887        param->mode = mode;
01888 
01889        tl_filter = mbfl_convert_filter_new2(
01890               &vtbl_tl_jisx0201_jisx0208,
01891               (int(*)(int, void*))next_filter->filter_function,
01892               (int(*)(void*))next_filter->filter_flush,
01893               next_filter);
01894        if (tl_filter == NULL) {
01895               mbfl_free(param);
01896               goto out;
01897        }
01898 
01899        tl_filter->opaque = param;
01900        next_filter = tl_filter;
01901 
01902        encoder = mbfl_convert_filter_new(
01903               string->no_encoding,
01904               mbfl_no_encoding_wchar,
01905               (int(*)(int, void*))next_filter->filter_function,
01906               (int(*)(void*))next_filter->filter_flush,
01907               next_filter); 
01908        if (encoder == NULL) {
01909               goto out;
01910        }
01911 
01912        /* feed data */
01913        p = string->val;
01914        n = string->len;
01915        if (p != NULL) {
01916               while (n > 0) {
01917                      if ((*encoder->filter_function)(*p++, encoder) < 0) {
01918                             break;
01919                      }
01920                      n--;
01921               }
01922        }
01923 
01924        mbfl_convert_filter_flush(encoder);
01925        result = mbfl_memory_device_result(&device, result);
01926 out:
01927        if (tl_filter != NULL) {
01928               if (tl_filter->opaque != NULL) {
01929                      mbfl_free(tl_filter->opaque);
01930               }
01931               mbfl_convert_filter_delete(tl_filter);
01932        }
01933 
01934        if (decoder != NULL) {
01935               mbfl_convert_filter_delete(decoder);
01936        }
01937 
01938        if (encoder != NULL) {
01939               mbfl_convert_filter_delete(encoder);
01940        }
01941 
01942        return result;
01943 }
01944 
01945 
01946 /*
01947  *  MIME header encode
01948  */
01949 struct mime_header_encoder_data {
01950        mbfl_convert_filter *conv1_filter;
01951        mbfl_convert_filter *block_filter;
01952        mbfl_convert_filter *conv2_filter;
01953        mbfl_convert_filter *conv2_filter_backup;
01954        mbfl_convert_filter *encod_filter;
01955        mbfl_convert_filter *encod_filter_backup;
01956        mbfl_memory_device outdev;
01957        mbfl_memory_device tmpdev;
01958        int status1;
01959        int status2;
01960        int prevpos;
01961        int linehead;
01962        int firstindent;
01963        int encnamelen;
01964        int lwsplen;
01965        char encname[128];
01966        char lwsp[16];
01967 };
01968 
01969 static int
01970 mime_header_encoder_block_collector(int c, void *data)
01971 {
01972        int n;
01973        struct mime_header_encoder_data *pe = (struct mime_header_encoder_data *)data;
01974 
01975        switch (pe->status2) {
01976        case 1:       /* encoded word */
01977               pe->prevpos = pe->outdev.pos;
01978               mbfl_convert_filter_copy(pe->conv2_filter, pe->conv2_filter_backup);
01979               mbfl_convert_filter_copy(pe->encod_filter, pe->encod_filter_backup);
01980               (*pe->conv2_filter->filter_function)(c, pe->conv2_filter);
01981               (*pe->conv2_filter->filter_flush)(pe->conv2_filter);
01982               (*pe->encod_filter->filter_flush)(pe->encod_filter);
01983               n = pe->outdev.pos - pe->linehead + pe->firstindent;
01984               pe->outdev.pos = pe->prevpos;
01985               mbfl_convert_filter_copy(pe->conv2_filter_backup, pe->conv2_filter);
01986               mbfl_convert_filter_copy(pe->encod_filter_backup, pe->encod_filter);
01987               if (n >= 74) {
01988                      (*pe->conv2_filter->filter_flush)(pe->conv2_filter);
01989                      (*pe->encod_filter->filter_flush)(pe->encod_filter);
01990                      mbfl_memory_device_strncat(&pe->outdev, "\x3f\x3d", 2); /* ?= */
01991                      mbfl_memory_device_strncat(&pe->outdev, pe->lwsp, pe->lwsplen);
01992                      pe->linehead = pe->outdev.pos;
01993                      pe->firstindent = 0;
01994                      mbfl_memory_device_strncat(&pe->outdev, pe->encname, pe->encnamelen);
01995                      c = (*pe->conv2_filter->filter_function)(c, pe->conv2_filter);
01996               } else {
01997                      c = (*pe->conv2_filter->filter_function)(c, pe->conv2_filter);
01998               }
01999               break;
02000 
02001        default:
02002               mbfl_memory_device_strncat(&pe->outdev, pe->encname, pe->encnamelen);
02003               c = (*pe->conv2_filter->filter_function)(c, pe->conv2_filter);
02004               pe->status2 = 1;
02005               break;
02006        }
02007 
02008        return c;
02009 }
02010 
02011 static int
02012 mime_header_encoder_collector(int c, void *data)
02013 {
02014        static int qp_table[256] = {
02015               1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x00 */
02016               1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x00 */
02017               1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
02018               0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 1, 0, 1, /* 0x10 */
02019               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
02020               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0x50 */
02021               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 */
02022               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0x70 */
02023               1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x80 */
02024               1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x90 */
02025               1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xA0 */
02026               1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xB0 */
02027               1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xC0 */
02028               1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xD0 */
02029               1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xE0 */
02030               1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1  /* 0xF0 */
02031        };
02032 
02033        int n;
02034        struct mime_header_encoder_data *pe = (struct mime_header_encoder_data *)data;
02035 
02036        switch (pe->status1) {
02037        case 11:      /* encoded word */
02038               (*pe->block_filter->filter_function)(c, pe->block_filter);
02039               break;
02040 
02041        default:      /* ASCII */
02042               if (c <= 0x00ff && !qp_table[(c & 0xff)]) { /* ordinary characters */
02043                      mbfl_memory_device_output(c, &pe->tmpdev);
02044                      pe->status1 = 1;
02045               } else if (pe->status1 == 0 && c == 0x20) {      /* repeat SPACE */
02046                      mbfl_memory_device_output(c, &pe->tmpdev);
02047               } else {
02048                      if (pe->tmpdev.pos < 74 && c == 0x20) {
02049                             n = pe->outdev.pos - pe->linehead + pe->tmpdev.pos + pe->firstindent;
02050                             if (n > 74) {
02051                                    mbfl_memory_device_strncat(&pe->outdev, pe->lwsp, pe->lwsplen);              /* LWSP */
02052                                    pe->linehead = pe->outdev.pos;
02053                                    pe->firstindent = 0;
02054                             } else if (pe->outdev.pos > 0) {
02055                                    mbfl_memory_device_output(0x20, &pe->outdev);
02056                             }
02057                             mbfl_memory_device_devcat(&pe->outdev, &pe->tmpdev);
02058                             mbfl_memory_device_reset(&pe->tmpdev);
02059                             pe->status1 = 0;
02060                      } else {
02061                             n = pe->outdev.pos - pe->linehead + pe->encnamelen + pe->firstindent;
02062                             if (n > 60)  {
02063                                    mbfl_memory_device_strncat(&pe->outdev, pe->lwsp, pe->lwsplen);              /* LWSP */
02064                                    pe->linehead = pe->outdev.pos;
02065                                    pe->firstindent = 0;
02066                             } else if (pe->outdev.pos > 0)  {
02067                                    mbfl_memory_device_output(0x20, &pe->outdev);
02068                             }
02069                             mbfl_convert_filter_devcat(pe->block_filter, &pe->tmpdev);
02070                             mbfl_memory_device_reset(&pe->tmpdev);
02071                             (*pe->block_filter->filter_function)(c, pe->block_filter);
02072                             pe->status1 = 11;
02073                      }
02074               }
02075               break;
02076        }
02077 
02078        return c;
02079 }
02080 
02081 mbfl_string *
02082 mime_header_encoder_result(struct mime_header_encoder_data *pe, mbfl_string *result)
02083 {
02084        if (pe->status1 >= 10) {
02085               (*pe->conv2_filter->filter_flush)(pe->conv2_filter);
02086               (*pe->encod_filter->filter_flush)(pe->encod_filter);
02087               mbfl_memory_device_strncat(&pe->outdev, "\x3f\x3d", 2);        /* ?= */
02088        } else if (pe->tmpdev.pos > 0) {
02089               if (pe->outdev.pos > 0) {
02090                      if ((pe->outdev.pos - pe->linehead + pe->tmpdev.pos) > 74) {
02091                             mbfl_memory_device_strncat(&pe->outdev, pe->lwsp, pe->lwsplen);
02092                      } else {
02093                             mbfl_memory_device_output(0x20, &pe->outdev);
02094                      }
02095               }
02096               mbfl_memory_device_devcat(&pe->outdev, &pe->tmpdev);
02097        }
02098        mbfl_memory_device_reset(&pe->tmpdev);
02099        pe->prevpos = 0;
02100        pe->linehead = 0;
02101        pe->status1 = 0;
02102        pe->status2 = 0;
02103 
02104        return mbfl_memory_device_result(&pe->outdev, result);
02105 }
02106 
02107 struct mime_header_encoder_data*
02108 mime_header_encoder_new(
02109     enum mbfl_no_encoding incode,
02110     enum mbfl_no_encoding outcode,
02111     enum mbfl_no_encoding transenc)
02112 {
02113        int n;
02114        const char *s;
02115        const mbfl_encoding *outencoding;
02116        struct mime_header_encoder_data *pe;
02117 
02118        /* get output encoding and check MIME charset name */
02119        outencoding = mbfl_no2encoding(outcode);
02120        if (outencoding == NULL || outencoding->mime_name == NULL || outencoding->mime_name[0] == '\0') {
02121               return NULL;
02122        }
02123 
02124        pe = (struct mime_header_encoder_data*)mbfl_malloc(sizeof(struct mime_header_encoder_data));
02125        if (pe == NULL) {
02126               return NULL;
02127        }
02128 
02129        mbfl_memory_device_init(&pe->outdev, 0, 0);
02130        mbfl_memory_device_init(&pe->tmpdev, 0, 0);
02131        pe->prevpos = 0;
02132        pe->linehead = 0;
02133        pe->firstindent = 0;
02134        pe->status1 = 0;
02135        pe->status2 = 0;
02136 
02137        /* make the encoding description string  exp. "=?ISO-2022-JP?B?" */
02138        n = 0;
02139        pe->encname[n++] = 0x3d;
02140        pe->encname[n++] = 0x3f;
02141        s = outencoding->mime_name;
02142        while (*s) {
02143               pe->encname[n++] = *s++;
02144        }
02145        pe->encname[n++] = 0x3f;
02146        if (transenc == mbfl_no_encoding_qprint) {
02147               pe->encname[n++] = 0x51;
02148        } else {
02149               pe->encname[n++] = 0x42;
02150               transenc = mbfl_no_encoding_base64;
02151        }
02152        pe->encname[n++] = 0x3f;
02153        pe->encname[n] = '\0';
02154        pe->encnamelen = n;
02155 
02156        n = 0;
02157        pe->lwsp[n++] = 0x0d;
02158        pe->lwsp[n++] = 0x0a;
02159        pe->lwsp[n++] = 0x20;
02160        pe->lwsp[n] = '\0';
02161        pe->lwsplen = n;
02162 
02163        /* transfer encode filter */
02164        pe->encod_filter = mbfl_convert_filter_new(outcode, transenc, mbfl_memory_device_output, 0, &(pe->outdev));
02165        pe->encod_filter_backup = mbfl_convert_filter_new(outcode, transenc, mbfl_memory_device_output, 0, &(pe->outdev));
02166 
02167        /* Output code filter */
02168        pe->conv2_filter = mbfl_convert_filter_new(mbfl_no_encoding_wchar, outcode, mbfl_filter_output_pipe, 0, pe->encod_filter);
02169        pe->conv2_filter_backup = mbfl_convert_filter_new(mbfl_no_encoding_wchar, outcode, mbfl_filter_output_pipe, 0, pe->encod_filter);
02170 
02171        /* encoded block filter */
02172        pe->block_filter = mbfl_convert_filter_new(mbfl_no_encoding_wchar, mbfl_no_encoding_wchar, mime_header_encoder_block_collector, 0, pe);
02173 
02174        /* Input code filter */
02175        pe->conv1_filter = mbfl_convert_filter_new(incode, mbfl_no_encoding_wchar, mime_header_encoder_collector, 0, pe);
02176 
02177        if (pe->encod_filter == NULL ||
02178            pe->encod_filter_backup == NULL ||
02179            pe->conv2_filter == NULL ||
02180            pe->conv2_filter_backup == NULL ||
02181            pe->conv1_filter == NULL) {
02182               mime_header_encoder_delete(pe);
02183               return NULL;
02184        }
02185 
02186        if (transenc == mbfl_no_encoding_qprint) {
02187               pe->encod_filter->status |= MBFL_QPRINT_STS_MIME_HEADER;
02188               pe->encod_filter_backup->status |= MBFL_QPRINT_STS_MIME_HEADER;
02189        } else {
02190               pe->encod_filter->status |= MBFL_BASE64_STS_MIME_HEADER;
02191               pe->encod_filter_backup->status |= MBFL_BASE64_STS_MIME_HEADER;
02192        }
02193 
02194        return pe;
02195 }
02196 
02197 void
02198 mime_header_encoder_delete(struct mime_header_encoder_data *pe)
02199 {
02200        if (pe) {
02201               mbfl_convert_filter_delete(pe->conv1_filter);
02202               mbfl_convert_filter_delete(pe->block_filter);
02203               mbfl_convert_filter_delete(pe->conv2_filter);
02204               mbfl_convert_filter_delete(pe->conv2_filter_backup);
02205               mbfl_convert_filter_delete(pe->encod_filter);
02206               mbfl_convert_filter_delete(pe->encod_filter_backup);
02207               mbfl_memory_device_clear(&pe->outdev);
02208               mbfl_memory_device_clear(&pe->tmpdev);
02209               mbfl_free((void*)pe);
02210        }
02211 }
02212 
02213 int
02214 mime_header_encoder_feed(int c, struct mime_header_encoder_data *pe)
02215 {
02216        return (*pe->conv1_filter->filter_function)(c, pe->conv1_filter);
02217 }
02218 
02219 mbfl_string *
02220 mbfl_mime_header_encode(
02221     mbfl_string *string,
02222     mbfl_string *result,
02223     enum mbfl_no_encoding outcode,
02224     enum mbfl_no_encoding encoding,
02225     const char *linefeed,
02226     int indent)
02227 {
02228        int n;
02229        unsigned char *p;
02230        struct mime_header_encoder_data *pe;
02231 
02232        mbfl_string_init(result);
02233        result->no_language = string->no_language;
02234        result->no_encoding = mbfl_no_encoding_ascii;
02235 
02236        pe = mime_header_encoder_new(string->no_encoding, outcode, encoding);
02237        if (pe == NULL) {
02238               return NULL;
02239        }
02240 
02241        if (linefeed != NULL) {
02242               n = 0;
02243               while (*linefeed && n < 8) {
02244                      pe->lwsp[n++] = *linefeed++;
02245               }
02246               pe->lwsp[n++] = 0x20;
02247               pe->lwsp[n] = '\0';
02248               pe->lwsplen = n;
02249        }
02250        if (indent > 0 && indent < 74) {
02251               pe->firstindent = indent;
02252        }
02253 
02254        n = string->len;
02255        p = string->val;
02256        while (n > 0) {
02257               (*pe->conv1_filter->filter_function)(*p++, pe->conv1_filter);
02258               n--;
02259        }
02260 
02261        result = mime_header_encoder_result(pe, result);
02262        mime_header_encoder_delete(pe);
02263 
02264        return result;
02265 }
02266 
02267 
02268 /*
02269  *  MIME header decode
02270  */
02271 struct mime_header_decoder_data {
02272        mbfl_convert_filter *deco_filter;
02273        mbfl_convert_filter *conv1_filter;
02274        mbfl_convert_filter *conv2_filter;
02275        mbfl_memory_device outdev;
02276        mbfl_memory_device tmpdev;
02277        int cspos;
02278        int status;
02279        enum mbfl_no_encoding encoding;
02280        enum mbfl_no_encoding incode;
02281        enum mbfl_no_encoding outcode;
02282 };
02283 
02284 static int
02285 mime_header_decoder_collector(int c, void* data)
02286 {
02287        const mbfl_encoding *encoding;
02288        struct mime_header_decoder_data *pd = (struct mime_header_decoder_data*)data;
02289 
02290        switch (pd->status) {
02291        case 1:
02292               if (c == 0x3f) {            /* ? */
02293                      mbfl_memory_device_output(c, &pd->tmpdev);
02294                      pd->cspos = pd->tmpdev.pos;
02295                      pd->status = 2;
02296               } else {
02297                      mbfl_convert_filter_devcat(pd->conv1_filter, &pd->tmpdev);
02298                      mbfl_memory_device_reset(&pd->tmpdev);
02299                      if (c == 0x3d) {            /* = */
02300                             mbfl_memory_device_output(c, &pd->tmpdev);
02301                      } else if (c == 0x0d || c == 0x0a) {      /* CR or LF */
02302                             pd->status = 9;
02303                      } else {
02304                             (*pd->conv1_filter->filter_function)(c, pd->conv1_filter);
02305                             pd->status = 0;
02306                      }
02307               }
02308               break;
02309        case 2:              /* store charset string */
02310               if (c == 0x3f) {            /* ? */
02311                      /* identify charset */
02312                      mbfl_memory_device_output('\0', &pd->tmpdev);
02313                      encoding = mbfl_name2encoding((const char *)&pd->tmpdev.buffer[pd->cspos]);
02314                      if (encoding != NULL) {
02315                             pd->incode = encoding->no_encoding;
02316                             pd->status = 3;
02317                      }
02318                      mbfl_memory_device_unput(&pd->tmpdev);
02319                      mbfl_memory_device_output(c, &pd->tmpdev);
02320               } else {
02321                      mbfl_memory_device_output(c, &pd->tmpdev);
02322                      if (pd->tmpdev.pos > 100) {        /* too long charset string */
02323                             pd->status = 0;
02324                      } else if (c == 0x0d || c == 0x0a) {      /* CR or LF */
02325                             mbfl_memory_device_unput(&pd->tmpdev);
02326                             pd->status = 9;
02327                      }
02328                      if (pd->status != 2) {
02329                             mbfl_convert_filter_devcat(pd->conv1_filter, &pd->tmpdev);
02330                             mbfl_memory_device_reset(&pd->tmpdev);
02331                      }
02332               }
02333               break;
02334        case 3:              /* identify encoding */
02335               mbfl_memory_device_output(c, &pd->tmpdev);
02336               if (c == 0x42 || c == 0x62) {             /* 'B' or 'b' */
02337                      pd->encoding = mbfl_no_encoding_base64;
02338                      pd->status = 4;
02339               } else if (c == 0x51 || c == 0x71) {      /* 'Q' or 'q' */
02340                      pd->encoding = mbfl_no_encoding_qprint;
02341                      pd->status = 4;
02342               } else {
02343                      if (c == 0x0d || c == 0x0a) {      /* CR or LF */
02344                             mbfl_memory_device_unput(&pd->tmpdev);
02345                             pd->status = 9;
02346                      } else {
02347                             pd->status = 0;
02348                      }
02349                      mbfl_convert_filter_devcat(pd->conv1_filter, &pd->tmpdev);
02350                      mbfl_memory_device_reset(&pd->tmpdev);
02351               }
02352               break;
02353        case 4:              /* reset filter */
02354               mbfl_memory_device_output(c, &pd->tmpdev);
02355               if (c == 0x3f) {            /* ? */
02356                      /* charset convert filter */
02357                      mbfl_convert_filter_reset(pd->conv1_filter, pd->incode, mbfl_no_encoding_wchar);
02358                      /* decode filter */
02359                      mbfl_convert_filter_reset(pd->deco_filter, pd->encoding, mbfl_no_encoding_8bit);
02360                      pd->status = 5;
02361               } else {
02362                      if (c == 0x0d || c == 0x0a) {      /* CR or LF */
02363                             mbfl_memory_device_unput(&pd->tmpdev);
02364                             pd->status = 9;
02365                      } else {
02366                             pd->status = 0;
02367                      }
02368                      mbfl_convert_filter_devcat(pd->conv1_filter, &pd->tmpdev);
02369               }
02370               mbfl_memory_device_reset(&pd->tmpdev);
02371               break;
02372        case 5:              /* encoded block */
02373               if (c == 0x3f) {            /* ? */
02374                      pd->status = 6;
02375               } else {
02376                      (*pd->deco_filter->filter_function)(c, pd->deco_filter);
02377               }
02378               break;
02379        case 6:              /* check end position */
02380               if (c == 0x3d) {            /* = */
02381                      /* flush and reset filter */
02382                      (*pd->deco_filter->filter_flush)(pd->deco_filter);
02383                      (*pd->conv1_filter->filter_flush)(pd->conv1_filter);
02384                      mbfl_convert_filter_reset(pd->conv1_filter, mbfl_no_encoding_ascii, mbfl_no_encoding_wchar);
02385                      pd->status = 7;
02386               } else {
02387                      (*pd->deco_filter->filter_function)(0x3f, pd->deco_filter);
02388                      if (c != 0x3f) {            /* ? */
02389                             (*pd->deco_filter->filter_function)(c, pd->deco_filter);
02390                             pd->status = 5;
02391                      }
02392               }
02393               break;
02394        case 7:              /* after encoded block */
02395               if (c == 0x0d || c == 0x0a) {      /* CR LF */
02396                      pd->status = 8;
02397               } else {
02398                      mbfl_memory_device_output(c, &pd->tmpdev);
02399                      if (c == 0x3d) {            /* = */
02400                             pd->status = 1;
02401                      } else if (c != 0x20 && c != 0x09) {             /* not space */
02402                             mbfl_convert_filter_devcat(pd->conv1_filter, &pd->tmpdev);
02403                             mbfl_memory_device_reset(&pd->tmpdev);
02404                             pd->status = 0;
02405                      }
02406               }
02407               break;
02408        case 8:              /* folding */
02409        case 9:              /* folding */
02410               if (c != 0x0d && c != 0x0a && c != 0x20 && c != 0x09) {
02411                      if (c == 0x3d) {            /* = */
02412                             if (pd->status == 8) {
02413                                    mbfl_memory_device_output(0x20, &pd->tmpdev);    /* SPACE */
02414                             } else {
02415                                    (*pd->conv1_filter->filter_function)(0x20, pd->conv1_filter);
02416                             }
02417                             mbfl_memory_device_output(c, &pd->tmpdev);
02418                             pd->status = 1;
02419                      } else {
02420                             mbfl_memory_device_output(0x20, &pd->tmpdev);
02421                             mbfl_memory_device_output(c, &pd->tmpdev);
02422                             mbfl_convert_filter_devcat(pd->conv1_filter, &pd->tmpdev);
02423                             mbfl_memory_device_reset(&pd->tmpdev);
02424                             pd->status = 0;
02425                      }
02426               }
02427               break;
02428        default:             /* non encoded block */
02429               if (c == 0x0d || c == 0x0a) {      /* CR LF */
02430                      pd->status = 9;
02431               } else if (c == 0x3d) {            /* = */
02432                      mbfl_memory_device_output(c, &pd->tmpdev);
02433                      pd->status = 1;
02434               } else {
02435                      (*pd->conv1_filter->filter_function)(c, pd->conv1_filter);
02436               }
02437               break;
02438        }
02439 
02440        return c;
02441 }
02442 
02443 mbfl_string *
02444 mime_header_decoder_result(struct mime_header_decoder_data *pd, mbfl_string *result)
02445 {
02446        switch (pd->status) {
02447        case 1:
02448        case 2:
02449        case 3:
02450        case 4:
02451        case 7:
02452        case 8:
02453        case 9:
02454               mbfl_convert_filter_devcat(pd->conv1_filter, &pd->tmpdev);
02455               break;
02456        case 5:
02457        case 6:
02458               (*pd->deco_filter->filter_flush)(pd->deco_filter);
02459               (*pd->conv1_filter->filter_flush)(pd->conv1_filter);
02460               break;
02461        }
02462        (*pd->conv2_filter->filter_flush)(pd->conv2_filter);
02463        mbfl_memory_device_reset(&pd->tmpdev);
02464        pd->status = 0;
02465 
02466        return mbfl_memory_device_result(&pd->outdev, result);
02467 }
02468 
02469 struct mime_header_decoder_data*
02470 mime_header_decoder_new(enum mbfl_no_encoding outcode)
02471 {
02472        struct mime_header_decoder_data *pd;
02473 
02474        pd = (struct mime_header_decoder_data*)mbfl_malloc(sizeof(struct mime_header_decoder_data));
02475        if (pd == NULL) {
02476               return NULL;
02477        }
02478 
02479        mbfl_memory_device_init(&pd->outdev, 0, 0);
02480        mbfl_memory_device_init(&pd->tmpdev, 0, 0);
02481        pd->cspos = 0;
02482        pd->status = 0;
02483        pd->encoding = mbfl_no_encoding_pass;
02484        pd->incode = mbfl_no_encoding_ascii;
02485        pd->outcode = outcode;
02486        /* charset convert filter */
02487        pd->conv2_filter = mbfl_convert_filter_new(mbfl_no_encoding_wchar, pd->outcode, mbfl_memory_device_output, 0, &pd->outdev);
02488        pd->conv1_filter = mbfl_convert_filter_new(pd->incode, mbfl_no_encoding_wchar, mbfl_filter_output_pipe, 0, pd->conv2_filter);
02489        /* decode filter */
02490        pd->deco_filter = mbfl_convert_filter_new(pd->encoding, mbfl_no_encoding_8bit, mbfl_filter_output_pipe, 0, pd->conv1_filter);
02491 
02492        if (pd->conv1_filter == NULL || pd->conv2_filter == NULL || pd->deco_filter == NULL) {
02493               mime_header_decoder_delete(pd);
02494               return NULL;
02495        }
02496 
02497        return pd;
02498 }
02499 
02500 void
02501 mime_header_decoder_delete(struct mime_header_decoder_data *pd)
02502 {
02503        if (pd) {
02504               mbfl_convert_filter_delete(pd->conv2_filter);
02505               mbfl_convert_filter_delete(pd->conv1_filter);
02506               mbfl_convert_filter_delete(pd->deco_filter);
02507               mbfl_memory_device_clear(&pd->outdev);
02508               mbfl_memory_device_clear(&pd->tmpdev);
02509               mbfl_free((void*)pd);
02510        }
02511 }
02512 
02513 int
02514 mime_header_decoder_feed(int c, struct mime_header_decoder_data *pd)
02515 {
02516        return mime_header_decoder_collector(c, pd);
02517 }
02518 
02519 mbfl_string *
02520 mbfl_mime_header_decode(
02521     mbfl_string *string,
02522     mbfl_string *result,
02523     enum mbfl_no_encoding outcode)
02524 {
02525        int n;
02526        unsigned char *p;
02527        struct mime_header_decoder_data *pd;
02528 
02529        mbfl_string_init(result);
02530        result->no_language = string->no_language;
02531        result->no_encoding = outcode;
02532 
02533        pd = mime_header_decoder_new(outcode);
02534        if (pd == NULL) {
02535               return NULL;
02536        }
02537 
02538        /* feed data */
02539        n = string->len;
02540        p = string->val;
02541        while (n > 0) {
02542               mime_header_decoder_collector(*p++, pd);
02543               n--;
02544        }
02545 
02546        result = mime_header_decoder_result(pd, result);
02547        mime_header_decoder_delete(pd);
02548 
02549        return result;
02550 }
02551 
02552 
02553 
02554 /*
02555  *  convert HTML numeric entity
02556  */
02557 struct collector_htmlnumericentity_data {
02558        mbfl_convert_filter *decoder;
02559        int status;
02560        int cache;
02561        int digit;
02562        int *convmap;
02563        int mapsize;
02564 };
02565 
02566 static int
02567 collector_encode_htmlnumericentity(int c, void *data)
02568 {
02569        struct collector_htmlnumericentity_data *pc = (struct collector_htmlnumericentity_data *)data;
02570        int f, n, s, r, d, size, *mapelm;
02571 
02572        size = pc->mapsize;
02573        f = 0;
02574        n = 0;
02575        while (n < size) {
02576               mapelm = &(pc->convmap[n*4]);
02577               if (c >= mapelm[0] && c <= mapelm[1]) {
02578                      s = (c + mapelm[2]) & mapelm[3];
02579                      if (s >= 0) {
02580                             (*pc->decoder->filter_function)(0x26, pc->decoder);     /* '&' */
02581                             (*pc->decoder->filter_function)(0x23, pc->decoder);     /* '#' */
02582                             r = 100000000;
02583                             s %= r;
02584                             while (r > 0) {
02585                                    d = s/r;
02586                                    if (d || f) {
02587                                           f = 1;
02588                                           s %= r;
02589                                           (*pc->decoder->filter_function)(mbfl_hexchar_table[d], pc->decoder);
02590                                    }
02591                                    r /= 10;
02592                             }
02593                             if (!f) {
02594                                    f = 1;
02595                                    (*pc->decoder->filter_function)(mbfl_hexchar_table[0], pc->decoder);
02596                             }
02597                             (*pc->decoder->filter_function)(0x3b, pc->decoder);            /* ';' */
02598                      }
02599               }
02600               if (f) {
02601                      break;
02602               }
02603               n++;
02604        }
02605        if (!f) {
02606               (*pc->decoder->filter_function)(c, pc->decoder);
02607        }
02608 
02609        return c;
02610 }
02611 
02612 static int
02613 collector_decode_htmlnumericentity(int c, void *data)
02614 {
02615        struct collector_htmlnumericentity_data *pc = (struct collector_htmlnumericentity_data *)data;
02616        int f, n, s, r, d, size, *mapelm;
02617 
02618        switch (pc->status) {
02619        case 1:
02620               if (c == 0x23) {     /* '#' */
02621                      pc->status = 2;
02622               } else {
02623                      pc->status = 0;
02624                      (*pc->decoder->filter_function)(0x26, pc->decoder);            /* '&' */
02625                      (*pc->decoder->filter_function)(c, pc->decoder);
02626               }
02627               break;
02628        case 2:
02629               if (c >= 0x30 && c <= 0x39) {      /* '0' - '9' */
02630                      pc->cache = c - 0x30;
02631                      pc->status = 3;
02632                      pc->digit = 1;
02633               } else {
02634                      pc->status = 0;
02635                      (*pc->decoder->filter_function)(0x26, pc->decoder);            /* '&' */
02636                      (*pc->decoder->filter_function)(0x23, pc->decoder);            /* '#' */
02637                      (*pc->decoder->filter_function)(c, pc->decoder);
02638               }
02639               break;
02640        case 3:
02641               s = 0;
02642               f = 0;
02643               if (c >= 0x30 && c <= 0x39) {      /* '0' - '9' */
02644                      if (pc->digit > 9) {
02645                             pc->status = 0;
02646                             s = pc->cache;
02647                             f = 1;
02648                      } else {
02649                             s = pc->cache*10 + c - 0x30;
02650                             pc->cache = s;
02651                             pc->digit++;
02652                      }
02653               } else {
02654                      pc->status = 0;
02655                      s = pc->cache;
02656                      f = 1;
02657                      n = 0;
02658                      size = pc->mapsize;
02659                      while (n < size) {
02660                             mapelm = &(pc->convmap[n*4]);
02661                             d = s - mapelm[2];
02662                             if (d >= mapelm[0] && d <= mapelm[1]) {
02663                                    f = 0;
02664                                    (*pc->decoder->filter_function)(d, pc->decoder);
02665                                    if (c != 0x3b) {     /* ';' */
02666                                           (*pc->decoder->filter_function)(c, pc->decoder);
02667                                    }
02668                                    break;
02669                             }
02670                             n++;
02671                      }
02672               }
02673               if (f) {
02674                      (*pc->decoder->filter_function)(0x26, pc->decoder);            /* '&' */
02675                      (*pc->decoder->filter_function)(0x23, pc->decoder);            /* '#' */
02676                      r = 1;
02677                      n = pc->digit;
02678                      while (n > 0) {
02679                             r *= 10;
02680                             n--;
02681                      }
02682                      s %= r;
02683                      r /= 10;
02684                      while (r > 0) {
02685                             d = s/r;
02686                             s %= r;
02687                             r /= 10;
02688                             (*pc->decoder->filter_function)(mbfl_hexchar_table[d], pc->decoder);
02689                      }
02690                      (*pc->decoder->filter_function)(c, pc->decoder);
02691               }
02692               break;
02693        default:
02694               if (c == 0x26) {     /* '&' */
02695                      pc->status = 1;
02696               } else {
02697                      (*pc->decoder->filter_function)(c, pc->decoder);
02698               }
02699               break;
02700        }
02701 
02702        return c;
02703 }
02704 
02705 int mbfl_filt_decode_htmlnumericentity_flush(mbfl_convert_filter *filter)
02706 {
02707        struct collector_htmlnumericentity_data *pc = (struct collector_htmlnumericentity_data *)filter;
02708        int n, s, r, d;
02709 
02710        if (pc->status) {
02711               switch (pc->status) {
02712               case 1: /* '&' */
02713                      (*pc->decoder->filter_function)(0x26, pc->decoder);            /* '&' */
02714                      break;
02715               case 2: /* '#' */
02716                      (*pc->decoder->filter_function)(0x26, pc->decoder);            /* '&' */
02717                      (*pc->decoder->filter_function)(0x23, pc->decoder);            /* '#' */
02718                      break;
02719               case 3: /* '0'-'9' */
02720                      (*pc->decoder->filter_function)(0x26, pc->decoder);            /* '&' */
02721                      (*pc->decoder->filter_function)(0x23, pc->decoder);            /* '#' */
02722 
02723                      s = pc->cache;
02724                      r = 1;
02725                      n = pc->digit;
02726                      while (n > 0) {
02727                             r *= 10;
02728                             n--;
02729                      }
02730                      s %= r;
02731                      r /= 10;
02732                      while (r > 0) {
02733                             d = s/r;
02734                             s %= r;
02735                             r /= 10;
02736                             (*pc->decoder->filter_function)(mbfl_hexchar_table[d], pc->decoder);
02737                      }
02738 
02739                      break;
02740               default:
02741                      break;
02742               }
02743        }
02744 
02745        pc->status = 0;
02746        pc->cache = 0;
02747        pc->digit = 0;
02748 
02749        return 0;
02750 }
02751 
02752 mbfl_string *
02753 mbfl_html_numeric_entity(
02754     mbfl_string *string,
02755     mbfl_string *result,
02756     int *convmap,
02757     int mapsize,
02758     int type)
02759 {
02760        struct collector_htmlnumericentity_data pc;
02761        mbfl_memory_device device;
02762        mbfl_convert_filter *encoder;
02763        int n;
02764        unsigned char *p;
02765 
02766        if (string == NULL || result == NULL) {
02767               return NULL;
02768        }
02769        mbfl_string_init(result);
02770        result->no_language = string->no_language;
02771        result->no_encoding = string->no_encoding;
02772        mbfl_memory_device_init(&device, string->len, 0);
02773 
02774        /* output code filter */
02775        pc.decoder = mbfl_convert_filter_new(
02776            mbfl_no_encoding_wchar,
02777            string->no_encoding,
02778            mbfl_memory_device_output, 0, &device);
02779        /* wchar filter */
02780        if (type == 0) {
02781               encoder = mbfl_convert_filter_new(
02782                   string->no_encoding,
02783                   mbfl_no_encoding_wchar,
02784                   collector_encode_htmlnumericentity, 0, &pc);
02785        } else {
02786               encoder = mbfl_convert_filter_new(
02787                   string->no_encoding,
02788                   mbfl_no_encoding_wchar,
02789                   collector_decode_htmlnumericentity, 
02790                      (int (*)(void*))mbfl_filt_decode_htmlnumericentity_flush, &pc);
02791        }
02792        if (pc.decoder == NULL || encoder == NULL) {
02793               mbfl_convert_filter_delete(encoder);
02794               mbfl_convert_filter_delete(pc.decoder);
02795               return NULL;
02796        }
02797        pc.status = 0;
02798        pc.cache = 0;
02799        pc.digit = 0;
02800        pc.convmap = convmap;
02801        pc.mapsize = mapsize;
02802 
02803        /* feed data */
02804        p = string->val;
02805        n = string->len;
02806        if (p != NULL) {
02807               while (n > 0) {
02808                      if ((*encoder->filter_function)(*p++, encoder) < 0) {
02809                             break;
02810                      }
02811                      n--;
02812               }
02813        }
02814        mbfl_convert_filter_flush(encoder);
02815        mbfl_convert_filter_flush(pc.decoder);
02816        result = mbfl_memory_device_result(&device, result);
02817        mbfl_convert_filter_delete(encoder);
02818        mbfl_convert_filter_delete(pc.decoder);
02819 
02820        return result;
02821 }
02822 
02823 /*
02824  * Local variables:
02825  * tab-width: 4
02826  * c-basic-offset: 4
02827  * End:
02828  */