iconvトランスコードプログラミングの概要


glibcはトランスコード関数iconvを持っていて、使いやすくて、識別できるコードが多くて、プログラムが符号化間の変換に関わる必要がある場合は、それを使うことを考慮することができます.iconvコマンドの使い方.

 
$ iconv --list # $ iconv -f GB2312 -t UTF-8 a.html > b.html # GB2312 a.html UTF-8 , b.html $ iconv -f GB2312 -t BIG5 a.html > b.html # GB2312 a.html BIG5 , b.html

iconvプログラミングは、次のglibcライブラリの呼び出しに関連します.

 

#include <iconv.h> iconv_t iconv_open(const char *tocode, const char *fromcode); int iconv_close(iconv_t cd); size_t iconv(iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);

iconv , iconv_open , iconv , iconv_close 。

 

 

iconv :


パラメータcdはiconv_でOpenは、返されるトランスコードハンドルを呼び出す.パラメータinbufは、トランスコードが必要なバッファを指す.パラメータinbytesleftはinbufが保存するトランスコードが必要なバイト数である.パラメータoutbufはトランスコード結果を格納する.パラメータoutbytesleftはoutbuf空間のサイズを格納します.
呼び出しに成功した場合、iconv変換を返すバイト数(不可逆呼び出しバイト数、可逆呼び出しバイト数は含まれません).そうでない場合は-1を返し、対応するerrnoを設定します.iconvはinbufを逐次スキャンし、文字を変換するたびにinbufを増やし、inbytesleftを減らし、結果をoutbufに格納し、結果バイト数をoutbytesleftに格納します.以下の場合、スキャンを停止して戻ります.
1.マルチバイトシーケンスが無効である場合、errnoはEILSEQであり、*inbufは最初の無効な文字を指す.2.inbufにバイトが残っているが、errnoはEINVALである.3.outbufスペースが足りなく、errnoはE 2 BIGである.4.正常な転換が整っている.
iconv関数の場合、2つの呼び出しがあります.
1.inbufまたは*inbufがNULL、outbufおよび*outbufがNULLでない場合、iconvは変換ステータスを初期状態に設定し、*outbufに変換シーケンスを保存します.outbufスペースが不足している場合、errnoはE 2 BIGに設定され、戻ります(size_t)(-1);2.inbufまたは*inbufはNULL、outbufまたは*outbufもNULL、iconvは遷移状態を初期状態に設定します.
iconvコマンドの使用は便利ですが、変換中に問題が発生すると変換が停止し、変換できないバイトシーケンスをスキップして変換を継続したい場合があります.次のプログラムでは、この機能を実現できます.
/** * siconv.cpp - A simple way to demostrate the usage of iconv calling** Report bugs to  [email protected] * July 15th, 2006*/#include #include #include #include #include #include #include #include #include
#ifdef DEBUG#define TRACE(fmt, args...) fprintf(stderr, "%s:%s:%d:"fmt,\__FILE__, __FUNCTION__, __LINE__, ##args)#else#define TRACE(fmt, args...)#endif
#define CONVBUF_SIZE 32767
extern int errno;
void print_err(const char *fmt, ...){ va_list ap;  va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap);}
int print_out(const char* buf, size_t num){ if (num != fwrite(buf, 1, num, stdout)) {  return -1; }  return 0;}
void print_usage() {  print_err("Usage: siconv -f encoding -t encoding [-c] "  "input-file");}
int iconv_string(const char *from, const char *to,      const char *src, size_t len,     ::std::string& result,      int c = 0, size_t buf_size = 512){ iconv_t cd;  char *pinbuf = const_cast< char* >(src); size_t inbytesleft = len; char *poutbuf = NULL; size_t outbytesleft = buf_size;  char *dst = NULL; size_t retbytes = 0; int done = 0; int errno_save = 0;  if ((iconv_t)-1 == (cd = iconv_open(to, from))) {  return -1; }  dst = new char[buf_size];  while(inbytesleft > 0 && !done)  {  poutbuf = dst;  outbytesleft = buf_size;    TRACE("TARGET - in:%p pin:%p left:%d", src, pinbuf, inbytesleft);  retbytes = iconv(cd, &pinbuf, &inbytesleft, &poutbuf, &outbytesleft);  errno_save = errno;    if (dst != poutbuf)  {//we have something to write   TRACE("OK - in:%p pin:%p left:%d done:%d buf:%d",     src, pinbuf, inbytesleft, pinbuf-src, poutbuf-dst);   result.append(dst, poutbuf-dst);  }     if (retbytes != (size_t)-1) {   poutbuf = dst;   outbytesleft = buf_size;   (void)iconv(cd, NULL, NULL, &poutbuf, &outbytesleft);      if (dst != poutbuf) {//we have something to write     TRACE("OK - in:%p pin:%p left:%d done:%d buf:%d",      src, pinbuf, inbytesleft, pinbuf-src, poutbuf-dst);    result.append(dst, poutbuf-dst);   }      errno_save = 0;   break;  }      TRACE("FAIL - in:%p pin:%p left:%d done:%d buf:%d",    src, pinbuf, inbytesleft, pinbuf-src, poutbuf-dst);    switch(errno_save)  {  case E2BIG:   TRACE("E E2BIG");   break;  case EILSEQ:   TRACE("E EILSEQ");   if (c) {    errno_save = 0;    inbytesleft = len-(pinbuf-src);//forward one illegal byte    inbytesleft--;    pinbuf++;    break;   }      done = 1;   break;  case EINVAL:   TRACE("E EINVAL");   done = 1;   break;  default:   TRACE("E Unknown:[%d]%s", errno, strerror(errno));   done = 1;   break;   }   }  delete[] dst; iconv_close(cd);  errno = errno_save; return (errno_save) ? -1 : 0;}
int conv_file_fd(const char* from, const char *to, int fd,     ::std::string& result, int c){ struct stat st; void *start;  if (0 != fstat(fd, &st)) {  return -1; }  start = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);  if (MAP_FAILED == start) {  return -1; }   if (iconv_string(from, to, (char*)start,   st.st_size, result, c, CONVBUF_SIZE) < 0) {  int errno_save = errno;  munmap(start, st.st_size);  TRACE("");  errno = errno_save;  return -1; }  munmap(start, st.st_size); return 0;}
int conv_file(const char* from, const char* to,      const char* filename, int c){ ::std::string result; FILE *fp;  if (NULL == (fp=fopen(filename, "rb"))) {  print_err("open file %s:[%d]%s", filename,    errno, strerror(errno));  return -1; }  if (conv_file_fd(from, to, fileno(fp), result, c) < 0)  {  print_err("conv file fd:[%d]%s", errno, strerror(errno));  fclose(fp);  return -1; }  print_out(result.data(), result.size()); fclose(fp); return 0;}
int main(int argc,char*argv[]){#ifdef TESTCASE::std::string strA=「ようこそ(welcome^^)首都北京へ.」::std::string strB=「We are chinese<=>私たちは中国人です」と叫ぶ.  ::std::string strC = strA.substr(0, 20) + strB.substr(0, 41); ::std::string result; if (iconv_string("GBK", "UTF-8", strC.data(), strC.size(), result, 1) < 0) {  TRACE("ERROR [%d]%s", errno, strerror(errno)); }  TRACE("CONVERSION RESULT:"); result.append(""); print_out(result.data(), result.size());  return 0;#else ::std::string from, to; ::std::string input_file; int o; int c = 0;  while (-1 != (c = getopt(argc, argv, "f:t:c"))) {  switch(c) {  case 'f':   from = optarg;   break;  case 't':   to = optarg;   break;  case 'c':   c = 1;   break;  default:   return -1;  } }  if (from.empty() || to.empty() || optind != (argc-1)) {  print_usage();  return -1; }  input_file = argv[optind++];  return conv_file(from.c_str(), to.c_str(),   input_file.c_str(), c);#endif}
ファイルが大きすぎてメモリバッファが足りない場合は、メモリイメージファイルで解決できます.iconvコマンドに対して、-cオプションを追加して、変換中に発生する可能性のある問題を無視します.

 
$ g++ -o siconv siconv.cpp

コマンドラインに-DDEBUGオプションを追加すると、デバッグ文がコンパイルされます.-DTESTCASEオプションを追加すると、iconv_のみコンパイルされます.string関数テストの場合.