1. 程式人生 > >linux 寬字元與多位元組字元之間的轉換

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;
}