C/400

126. UTF-8 にエンコードするには

RPG での文字のエンコードの方法として「 323. ASCII エンコードするには 」を
紹介したが、それでは C 言語でのエンコードはやさしいかというとそうでもない。
もちろん C 言語でもエンコードする必要に迫られることがあるのでその方法を紹介しよう。

【 TESTENCD2 】
0001.00 #include                                                    
0002.00 #include                                                   
0003.00 #include                                                   
0004.00 #include  /* triml */                                    
0005.00 #include     /* toupper */                                  
0006.00 #include                                                  
0007.00 #include                                                 
0008.00                                                                      
0009.00 #define TRUE         0                                               
0010.00 #define FALSE       -1                                               
0011.00 /*( UTF 変数 )*/                                                     
0012.00 #define UTF8      1208                                               
0013.00 #define USA          0                                               
0014.00 #define JPN          1                                               
0015.00 #define CHS          2                                               
0016.00 #define CHT          3                                               
0017.00 #define JPN5035      8                                               
0018.00                                                                      
0019.00 int   encode(char* fromstr, char* tostr, int CNTRY, char* URLPath);  
0020.00 char* encodeURIComponentUTF(char* utf8_str);                         
0021.00 int   toUTF8(char* ebcbuf, char* unibuf, int CNTRY);  /* UNI_CODE */ 
0022.00 int   toEBCDIC(char* ebcbuf, char* ascbuf, char* table, /* CVTMOD4 */
0023.00                                            char* tbllib, int bSiSo); 
0024.00                                                                       
0025.00 void main(void){                                                      
0026.00   char fromstr[128], tostr[128], URLPath[128];                        
0027.00                                                                       
0028.00   printf("** TESTENCD2: UTF8 エンコードのテスト **?n");               
0029.00   getchar();                                                          
0030.00                                                                       
0031.00    strcpy(fromstr, "/TEMP/MY#FILE.TMP");                              
0032.00    strcpy(URLPath, "http;//www.officequattro.com");                   
0033.00    if(encode(fromstr, tostr, JPN5035, URLPath) == FALSE){/* エラー */ 
0034.00          printf("HTTPSRV[%d] %s: エンコードでエラーがありました。 ",  
0035.00            __LINE__, fromstr);                                        
0036.00          getchar();                                                   
0037.00          exit(-1);                                                    
0038.00    }/* エラー */                                                      
0039.00    printf("[%d] 文字列 %s は ?n", __LINE__, fromstr);                 
0040.00    printf("[%d] %s とエンコードされました。 ?n", __LINE__, tostr);    
0041.00    getchar();                                                         
0042.00    exit(0);                                                           
0043.00 }                                                                     
0044.00                                                                       
0045.00 /*****************************************************************/   
0046.00 int   encode(char* fromstr, char* tostr, int CNTRY, char* URLPath)    
0047.00 /*****************************************************************/   
0048.00 {                                                                             
0049.00    char utfbuf[2048];                                                         
0050.00    _Decimal(5,0)  dclen, outlen = 0;                                          
0051.00    _Decimal(5,0)  maxotl = 2048;                                              
0052.00    int len;                                                                   
0053.00                                                                               
0054.00    memset(utfbuf, 0, sizeof(utfbuf));                                         
0055.00    if((strstr(URLPath, "ea-jp")) != NULL){/* 英語から日本語 */                
0056.00      memset(utfbuf, 0, sizeof(utfbuf));                                       
0057.00      len = strlen(fromstr);                                                   
0058.00      dclen = (_Decimal(5,0))len;                                              
0059.00      QDCXLATE(&dclen, fromstr, "QASCII    ", "QSYS      ", utfbuf,            
0060.00                  &maxotl, &outlen, "*JPN      ", "N", "*EA       ");          
0061.00    }/* 英語から日本語 */                                                      
0062.00    else{/* それ以外 */                                                        
0063.00      if(toUTF8(fromstr, utfbuf, CNTRY) == FALSE){/* エラー */                 
0064.00        printf("HTTPSRV[%d] UTF8 変換でエラーがありました。 ?n%s?n", __LINE__, 
0065.00         fromstr);                                                             
0066.00        return FALSE;                                                          
0067.00      }/* エラー */                                                            
0068.00    }/* それ以外 */                                                            
0069.00    strcpy(tostr, encodeURIComponentUTF(utfbuf));                              
0070.00    return TRUE;                                                               
0071.00 }                                                                             
0072.00 /*****************************************/                          
0073.00 char* encodeURIComponentUTF(char* utf8_str)                          
0074.00 /*****************************************/                          
0075.00 /* JavaScript の encodeURIComponent() と同じようにエンコードする */  
0076.00 {                                                                    
0077.00   char *ptr;                                                         
0078.00   char ebc_str[5], utf_str[5];                                       
0079.00                                                                      
0080.00   ptr = utf8_str;                                                    
0081.00   while(*ptr){/*while*/                                              
0082.00 #pragma convert(850)                                                 
0083.00     if('0' <= *ptr && *ptr <= '9' ||                                 
0084.00        'A' <= *ptr && *ptr <= 'Z' ||                                 
0085.00        'a' <= *ptr && *ptr <= 'z' ||                                 
0086.00        *ptr == '-' || *ptr == '_' || *ptr == '.' || *ptr == '!' ||   
0087.00        *ptr == '…?' || *ptr == '*' || *ptr == '?'')                   
0088.00 #pragma convert(0)                                                   
0089.00     {/* エンコードの必要なし */                                      
0090.00       memcpy(utf_str, ptr, 1);                                       
0091.00       utf_str[1] = 0x00;                                             
0092.00       toEBCDIC(ebc_str, utf_str, "EBCDIC5035", "ASNET.COM ", TRUE);  
0093.00       memcpy(ptr, ebc_str, 1);                                       
0094.00       ptr ++;                                                        
0095.00       continue;                                                      
0096.00     }/* エンコードの必要なし */                       
0097.00     else{/* エンコードが必要 */                       
0098.00       memmove(ptr + 3, ptr + 1, strlen(ptr + 1) + 1); 
0099.00       sprintf(ebc_str, "%%%02X", *ptr);               
0100.00       memcpy(ptr, ebc_str, 3);                        
0101.00       ptr += 3;                                       
0102.00     }/* エンコードが必要 */                           
0103.00   }/*while*/                                          
0104.00   return utf8_str;                                    
0105.00 }                                                     
【 解説 】

実行してみると

   ** TESTENCD2: UTF8 エンコードのテスト **              
 >                                                       
   [39] 文字列 /TEMP/MY#FILE.TMP は                      
   [40] %2FTEMP%2FMY%23FILE.TMP とエンコードされました。 

のように表示される。
テスト用の文字列「 /TEMP/MY#FILE.TMP 」の文字「 / 」と「 # 」の
部分だけがエンコードされていることがわかる。
/ は UTF-8 では 0x'2f' なので %2F とエンコードされ、
# は UTF-8 では 0x'23' なので %23 とエンコードされる。
エンコードのコアの部分は関数: encodeURIComponentUTF で実行されるので
これを利用するなり読み取って欲しい。

なおこの TESTENCD2 は弊社の *SRVPGM: UNI_CODE と CVTMO4 を
バインドする必要があるので読者の環境ではコンパイルすることはできないが
ソースを学習するために紹介した。

AutoWebのユーザーであれば

   CRTCMOD MODULE(QTEMP/TESTENCD2) SRCFILE(R610SRC/QCSRC) AUT(*ALL)

   CRTPGM PGM(TEST.COM/TESTENCD2) MODULE(QTEMP/TESTENCD2) BNDSRVPGM((ASNET.OM/UNI_CODE) (ASNET.COM/CVTMOD4))       ACTGRP(*NEW) AUT(*ALL)   

によってコンパイルすることができる。