iconvで文字コード変換と、16進数文字列変換


```cpp:a.cpp


#include <stdio.h>
#include <stdlib.h>
#include <iconv.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>

#include <string>

std::string encode( const u_char *input_string, size_t input_length, std::string input_code, std::string output_code ) {
	
	if( input_string == NULL ) {
		
		fprintf( stderr, "input string is empty.\n" );
		return( "" );
		
	}
	
	if( input_length == 0 ) {
		
		fprintf( stderr, "input length is zero.\n" );
		return( "" );
		
	}
	
	if( input_code.empty() ) {
		
		// iconvに文字列判定機能は無い。
		// 入力した文字列の文字コードを与える必要がある。
		fprintf( stderr, "input code is empty.\n" );
		return( "" );
		
	}
	
	if( output_code.empty() ) {
		
		// 変換したい文字コードが無い場合は、
		// ひとまず、自分の環境の文字コードに変換されるようにしておく。
		output_code = "UTF-8";
		
	}
	
	iconv_t ic;
	
	size_t str_in_length = input_length;
	size_t str_out_length = input_length * 3; // 変換後のバイト数がどうなるか分からない。1バイトが3バイトになることを考慮しておく。
	
	char str_in[str_in_length+1];
	char str_out[str_out_length+1];
	
	memset( str_in, 0, sizeof( str_in ) );
	memset( str_out, 0, sizeof( str_out ) );
	
	// const u_char -> char
	for( size_t i = 0; i < input_length; ++i ) {
		
		str_in[i] = (char)input_string[i];
		
	}
	
	// iconvに渡すのは、charの配列の先頭を指すポインタ、のポインタ。
	char *ptr_in  = str_in;
	char *ptr_out = str_out;
	
	errno = 0;
	
	ic = iconv_open( output_code.c_str(), input_code.c_str() );
	
	if( errno ) {
		
		fprintf( stderr, "iconv_open failed. %s\n", strerror( errno ) );
		return( "" );
		
	}
	
	// それぞれポインタを渡す。
	iconv( ic, &ptr_in, &str_in_length, &ptr_out, &str_out_length );
	
	if( errno ) {
		
		fprintf( stderr, "iconv failed. %s\n", strerror( errno ) );
		
		iconv_close( ic );
		return( "" );
		
	} else {
		
		iconv_close( ic );
		return( str_out );
		
	}
	
}
	
int main( int argc, char **argv ) {
	
	// input_stringで期待する文字列は、16進数文字列。大文字でも小文字でもかまわない。
	if( argc != 4 ) {
		
		printf( "./a.out input_code output_code input_string\n\n" );
		printf( "example:\n" );
		printf( "\t./a.out SHIFT-JIS UTF-8 4e69636520626f61742e\n\n" );
		return( 1 );
		
	}
	
	// 16進文字列を、数値に戻し、charの配列にする。
	size_t input_length = strlen( argv[3] );
	size_t input_length_half = input_length / 2;
	
	if( input_length_half == 0 ) {
		
		// 1文字も無い?
		fprintf( stderr, "input_string empty.\n" );
		return( 1 );
		
	}
	
	u_char input_string[input_length_half];
	u_char *input_string_p = input_string;
	
	for( size_t i = 0, ii = 0; i < input_length_half; ++i, ii += 2 ) {
		
		char tmp[2];
		strncpy( tmp, argv[3] + ii, 2 );
		tmp[2] = '\0';
		
		long num = strtol( tmp, NULL, 16 );
		*input_string_p++ = (u_char)num;
		
	}
	
	std::string ret = encode( input_string, input_length_half, argv[1], argv[2] );
	
	printf( "%s\n", ret.c_str() );
	
	return( 0 );
	
}


```

ノリで書いてみました。

細かいエラーチェックはしてないです。

実行すると以下のような感じに。

<pre>
[todanano@localhost samba]$ g++ ./a.cpp
[todanano@localhost samba]$
[todanano@localhost samba]$
[todanano@localhost samba]$ ./a.out SHIFT-JIS UTF-8 82a0829f5e8160905382aa82d282e582f182d282e582f182b782e982f182b682e1829f5e8160
あぁ^～心がぴょんぴょんするんじゃぁ^～
[todanano@localhost samba]$
[todanano@localhost samba]$
[todanano@localhost samba]$ ./a.out UTF-8 UTF-8 e38182e381815eefbd9ee5bf83e3818ce381b4e38287e38293e381b4e38287e38293e38199e3828be38293e38198e38283e381815eefbd9e
あぁ^～心がぴょんぴょんするんじゃぁ^～
[todanano@localhost samba]$
[todanano@localhost samba]$
[todanano@localhost samba]$ ./a.out EUC-JP UTF-8 a4a2a4a15ea1c1bfb4a4aca4d4a4e7a4f3a4d4a4e7a4f3a4b9a4eba4f3a4b8a4e3a4a15ea1c1
あぁ^～心がぴょんぴょんするんじゃぁ^～
[todanano@localhost samba]$
</pre>


文字列を16進数文字列にするには、以下のサイト様とかで。

http://kujirahand.com/web-tools/Hex.php?ve=&charset=EUC-JP