
// stdafx.cpp : 只包括标准包含文件的源文件
// iconvtest.pch 将作为预编译头
// stdafx.obj 将包含预编译类型信息

#include "stdafx.h"

/*
iconv（）将返回（size_t）-1并设置errno来指示错误。

errno值如下:
[EILSEQ]
	输入转换由于不属于输入代码集的输入字节而停止。
[E2BIG]
	由于输出缓冲区空间不足，输入转换停止。
[EINVAL]
	由于输入缓冲区末尾的字符或移位序列不完整，导致输入转换停止。

如果出现以下情况，iconv（）函数可能失败：
[EBADF]
	该CD的说法是不是有效的打开转换描述。
*/


int ChangeCode(
	const char* pFromCode,
	const char* pToCode,
	const char* pInBuf,
	size_t* iInLen,
	char* pOutBuf,
	size_t* iOutLen)
{
	int iRet;
	// 打开字符集转换;
	iconv_t hIconv = iconv_open(pToCode, pFromCode);
	if (-1 == (int)hIconv)
	{
		return -1;//打开失败，可能不支持的字符集
	}
	//开始转换
	iRet = iconv(hIconv, (const char**)(&pInBuf), iInLen, (char**)(&pOutBuf), iOutLen);
	//关闭字符集转换
	iconv_close(hIconv);
	return iRet;
}

/************************************************************************/
/*  函数：[1/22/2018 Home];
/*  描述：;
/*  参数：;
/*  	[IN] ：;
/*  	[OUT] ：;
/*  	[IN/OUT] ：;
/*  返回：void;
/*  注意：;
/*  示例：;
/*
/*  修改：;
/*  日期：;
/*  内容：;
/************************************************************************/
std::string convert(const char *from, const char* to, const char* inbuf, const size_t &inbufsize)
{
	int iconv_ret = 0;
	// 打开字符集转换;
	iconv_t hIconv = iconv_open(to, from);
	if (-1 == (int)hIconv)
		return "";//打开失败，可能不支持的字符集

	size_t insize = inbufsize;
	std::string strout;
	// 循环利用;
	size_t outsize = 512;
	// 513多一位用做字符结束符;
	char out[513] = { 0 };

	while (insize > 0)
	{
		outsize = 512;
		memset(out, 0, outsize);
		// out地址保存不变,以便重复使用;
		char *p = out;

		// 开始转换;
		iconv_ret = iconv(hIconv, (const char**)(&inbuf), &insize, &p, &outsize);
		if (((iconv_ret == (size_t)-1) && (E2BIG == errno)) || (iconv_ret != (size_t)-1))
		{
			// out和p地址不同, p-out指针相减得到长度;
			//strout.append(out, p - out);
			strout.insert(strout.size(), out, p - out);
		}
	}

	//关闭字符集转换
	iconv_close(hIconv);

	return strout;
}

std::string convertEx(const char *from, const char* to, const char* inbuf, const size_t &inbufsize)
{
	int iconv_ret = 0;
	// 打开字符集转换;
	iconv_t hIconv = iconv_open(to, from);
	if (-1 == (int)hIconv)
		return "";//打开失败，可能不支持的字符集

	int status = 0;
	iconv(hIconv, NULL, NULL, NULL, NULL);
	size_t insize = inbufsize;
	std::string strout;
	// 循环利用;
	size_t outsize = 512;
	// 513多一位用做字符结束符;
	char out[513] = { 0 };

	while (insize > 0)
	{
		outsize = 512;
		memset(out, 0, outsize);
		// out地址保存不变,以便重复使用;
		char *p = out;

		// 开始转换;
		iconv_ret = iconv(hIconv, (const char**)(&inbuf), &insize, &p, &outsize);
		if (out != p)
		{
			int saved_errno = errno;
			strout.insert(strout.size(), out, p - out);
			errno = saved_errno;
		}

		if (iconv_ret == (size_t)(-1))
		{
			if (errno == EILSEQ)
			{//	输入中遇到无效的多字节序列;
				int one = 1;
				// 非法序列丢弃并继续;
				iconvctl(hIconv, ICONV_SET_DISCARD_ILSEQ, &one);
				status = -3;
			}
			else if (errno == EINVAL)
			{// 输入中遇到了一个不完整的多字节序列;
				if (inbufsize == 0)
				{
					status = -4;
					goto done;
				}
				else
				{
					break;
				}
			}
			else if (errno == E2BIG)
			{// *outbuf没有足够的空间;
				status = -5;
				//goto done;
			}
			else {
				status = -6;
				goto done;
			}
		}
		/*if (((iconv_ret == (size_t)-1) && (E2BIG == errno)) || (iconv_ret != (size_t)-1))
		{
			// out和p地址不同, p-out指针相减得到长度;
			//strout.append(out, p - out);
			strout.insert(strout.size(), out, p - out);
		}*/
	}

done:
	//关闭字符集转换
	iconv_close(hIconv);

	return strout;
}

/************************************************************************/
/*  函数：[1/21/2018 Jeff];
/*  描述：对字符串进行语言编码转换;
/*  参数：;
/*  	[IN] from：原始编码，比如"GB2312",的按照iconv支持的写;
/*  	[IN] to：转换的目的编码;
/*  	[IN] save：转换后的数据保存到这个指针里，需要在外部分配内存;
/*  	[IN] savelen：存储转换后数据的内存大小;
/*  	[OUT] src：原始需要转换的字符串;
/*  	[OUT] srclen：原始字符串长度;
/*  返回：void;
/*  注意：;
/*  示例：;
/*
/*  修改：;
/*  日期：;
/*  内容：;
/************************************************************************/
int convert(const char *from, const char *to, char* save, int savelen, char *src, int srclen)
{
	iconv_t cd;
	char   *inbuf = src;
	char *outbuf = save;
	size_t outbufsize = savelen;
	int status = 0;
	size_t  savesize = 0;
	size_t inbufsize = srclen;
	const char* inptr = inbuf;
	size_t      insize = inbufsize;
	char* outptr = outbuf;
	size_t outsize = outbufsize;

	cd = iconv_open(to, from);
	iconv(cd, NULL, NULL, NULL, NULL);
	if (inbufsize == 0) {
		status = -1;
		goto done;
	}
	while (insize > 0)
	{
		size_t res = iconv(cd, (const char**)&inptr, &insize, &outptr, &outsize);
		if (outptr != outbuf)
		{
			int saved_errno = errno;
			int outsize = outptr - outbuf;
			strncpy(save + savesize, outbuf, outsize);
			errno = saved_errno;
		}
		if (res == (size_t)(-1))
		{
			if (errno == EILSEQ)
			{
				int one = 1;
				iconvctl(cd, ICONV_SET_DISCARD_ILSEQ, &one);
				status = -3;
			}
			else if (errno == EINVAL)
			{
				if (inbufsize == 0)
				{
					status = -4;
					goto done;
				}
				else
				{
					break;
				}
			}
			else if (errno == E2BIG)
			{
				status = -5;
				goto done;
			}
			else {
				status = -6;
				goto done;
			}
		}
	}
	status = strlen(save);
done:
	iconv_close(cd);
	return status;
}
