linux 寬字元與多位元組字元之間的轉換
最近再調linux下證書驗證問題,由於要對客戶端傳送過來的證書在伺服器上與根證書進行認證,所以在讀取證書、驗證證書時設計到了編碼轉換問題。在windows下,使用MultiByteToWideChar和WideCharToMultiByte沒有問題,但在linux下,不存在這兩個函式,於是我們想到了用wcstombs和mbstowcs兩個函式,但經試驗,不能得到正確的結果,後來,經分析,得到,在windows下wchar_t為2位元組,而在linux wchar_t為4位元組,我們提取的證書編碼為2位元組的寬字元,所以不能正確地進行轉換。不得不,只能使用libiconv進行轉換。
iconv函式族的標頭檔案是iconv.h。
#include <iconv.h>
iconv函式族有三個函式,原型如下:
(1) iconv_t iconv_open(const char *tocode, const char *fromcode);
此函式說明將要進行哪兩種編碼的轉換,tocode是目標編碼,fromcode是原編碼,該函式返回一個轉換控制代碼,供以下兩個函式使用。
(2) size_t iconv(iconv_t cd,char **inbuf,size_t *inbytesleft,char **outbuf,size_t *outbytesleft);
此函式從inbuf中讀取字元,轉換後輸出到outbuf中,inbytesleft用以記錄還未轉換的字元數,outbytesleft用以記錄輸出緩衝的剩餘空間。 (3) int iconv_close(iconv_t cd);
此函式用於關閉轉換控制代碼,釋放資源。
經過測試,使用這轉換函式需要注意的有以下幾點:
1、寬位元組存在big-endian和little-endian之分,那使用寬字元編碼時使用的編碼名字也不一樣,例如我們用的UCS-2編碼,那有“UCS-2”和“UCS-2-INTERNAL”之分;
2、iconv中的兩個長度在執行完函式後,分別為分配快取剩餘位元組的大小;
3、而兩個指標分別指向轉換後字串的尾部,所以在進行轉換之前,應該保留快取的原始指標,在轉換後,用這兩個指標減去原始指標,那就是已轉換的位元組長度和轉換後的位元組長度。
下面是我測試的程式碼,程式寫的不怎麼考究,呵呵!
#include <iconv.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <locale.h>
#define BUFLEN 200
char outBuf[BUFLEN];
//char inBuf[BUFLEN]="CN";
char inBuf[BUFLEN]="/x43/x00/x4e/x00/x00/x00";
//char inBuf[BUFLEN]="/x7a/x7a/x51/x9b/x00/x00";
int main(){
char *pIn = inBuf;
char *pOut = outBuf;
iconv_t cd;
int inLen = 4, outLen = BUFLEN;
int retSize = 0;
cd = iconv_open("UTF-8","UCS-2-INTERNAL");
// cd = iconv_open("UCS-2-INTERNAL","UTF-8");
if ((iconv_t)-1 == cd){
printf("Donot support this convert../n");
return -1;
}
if ((size_t)-1 == (retSize= iconv(cd, &pIn, (size_t *)&inLen, &pOut,(size_t *)&outLen))){
if (E2BIG == errno)
printf(" E2BIG errno %d/n", errno);
if (EILSEQ == errno)
printf("EILSEQ errno %d/n", errno);
if (EINVAL == errno)
printf("EINVAL errno %d/n", errno);
printf("convert WCHAR to multi error/n");
return -1;
}
if (outLen > 0){
printf("/n/n outBuf:");
int i = 0;
for (i = 0; i < 200; i++){
printf("%02x ", outBuf[i]);
}
printf("/n/n inBuf:");
for (i = 0; i < 200; i++){
printf("%02x ", inBuf[i]);
}
printf("/n/n");
}
printf("out buf: %s outLen: %d retSize: %d inLen: %d/n", pOut, outLen, retSize, inLen);
printf("pInbuf: %s/n", pIn);
iconv_close(cd);
return 0;
}