Index: /trunk/include/cf_codec.h
===================================================================
--- /trunk/include/cf_codec.h	(revision 87)
+++ /trunk/include/cf_codec.h	(revision 88)
@@ -7,10 +7,10 @@
  * @example codec.c
  */
+#ifndef __CF_CODEC_H__
+#define __CF_CODEC_H__
+
 #include "cf_base.h"
 
 #include <stddef.h>
-
-#ifndef __CF_CODEC_H__
-#define __CF_CODEC_H__
 
 #ifdef __cplusplus
@@ -19,12 +19,22 @@
 
 CF_EXPORT int
-CF_Codec_Hex_Encode		(const unsigned char	* bin,
-						 const size_t			len,
-						 char					* hex);
+CF_Codec_Hex_Encode			(const unsigned char	* bin,
+							 const size_t			len,
+							 char					* hex);
 
 CF_EXPORT int
-CF_Codec_Hex_Decode		(const char		* hex,
-						 unsigned char	* bin,
-						 size_t			* len);
+CF_Codec_Hex_Decode			(const char		* hex,
+							 unsigned char	* bin,
+							 size_t			* len);
+
+CF_EXPORT int
+CF_Codec_Base64_Encode		(const unsigned char	* bin,
+							 const size_t			len,
+							 char					* base64);
+
+CF_EXPORT int
+CF_Codec_Base64_Decode		(const char		* base64,
+							 unsigned char	* bin,
+							 size_t			* len);
 
 #ifdef __cplusplus
Index: /trunk/include/cf_error.h
===================================================================
--- /trunk/include/cf_error.h	(revision 87)
+++ /trunk/include/cf_error.h	(revision 88)
@@ -104,4 +104,5 @@
 #define CF_ERROR_CODEC_INVALID_ARGS			CF_ERROR_CODEC - 1
 #define CF_ERROR_CODEC_NOT_HEXSTRING		CF_ERROR_CODEC - 2
+#define CF_ERROR_CODEC_NOT_BASE64			CF_ERROR_CODEC - 3
 /* }}} codec */
 
Index: /trunk/src/cf_codec.c
===================================================================
--- /trunk/src/cf_codec.c	(revision 87)
+++ /trunk/src/cf_codec.c	(revision 88)
@@ -13,12 +13,63 @@
 		return CF_ERROR_CODEC_INVALID_ARGS
 
-#define IS_NUMBER(x)		(x >= '0' && x <= '9')
-#define IS_LOWERCASE(x)		(x >= 'a' && x <= 'f')
-#define IS_UPPERCASE(x)		(x >= 'A' && x <= 'F')
-
-typedef	unsigned char __uchar;
-
-/**
- * 바이너리 데이터를 16진수 문자열로 변환
+const static unsigned char g_ascii_HexDecode[] = {
+#define ASCN	'0'	/* ascii number */
+#define ASCU	'A' /* ascii upper */
+#define ASCL	'a' /* ascii lower */
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	/*  00 -  15 */
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	/*  16 -  31 */
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	/*  32 -  47 */
+	ASCN,ASCN,ASCN,ASCN,ASCN,ASCN,ASCN,ASCN,ASCN,ASCN,0x00,0x00,0x00,0x00,0x00,0x00,	/*  48 -  63 */
+	0x00,ASCU,ASCU,ASCU,ASCU,ASCU,ASCU,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	/*  64 -  79 */
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	/*  80 -  95 */
+	0x00,ASCL,ASCL,ASCL,ASCL,ASCL,ASCL,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	/*  96 - 111 */
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	/* 112 - 127 */
+	/* end of ascii character */
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	/* 128 - 143 */
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	/* 144 - 159 */
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	/* 160 - 175 */
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	/* 176 - 191 */
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	/* 192 - 207 */
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	/* 208 - 223 */
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	/* 224 - 239 */
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	/* 240 - 255 */
+};
+
+const static char g_table_Base64Encode[] = {
+#define PADDING_CHAR_INDEX	64
+	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',		/* 00 - 07 */
+	'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',		/* 08 - 15 */
+	'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',		/* 16 - 23 */
+	'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',		/* 24 - 31 */
+	'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',		/* 32 - 39 */
+	'o', 'p', 'q', 'r', 's', 't', 'u', 'v',		/* 40 - 47 */
+	'w', 'x', 'y', 'z', '0', '1', '2', '3',		/* 48 - 55 */
+	'4', '5', '6', '7', '8', '9', '+', '/',		/* 56 - 63 */
+	'='											/* padding */
+};
+
+const static unsigned char g_ascii_Base64Decode[] = {
+	99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,	/*  00 -  15 */
+	99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,	/*  16 -  31 */
+	99,99,99,99,99,99,99,99,99,99,99,62,99,99,99,63,	/*  32 -  47 */
+	52,53,54,55,56,57,58,59,60,61,99,99,99,64,99,99,	/*  48 -  63 */
+	99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,	/*  64 -  79 */
+	15,16,17,18,19,20,21,22,23,24,25,99,99,99,99,99,	/*  80 -  95 */
+	99,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,	/*  96 - 111 */
+	41,42,43,44,45,46,47,48,49,50,51,99,99,99,99,99,	/* 112 - 127 */
+	/* end of ascii character */
+	99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,	/* 128 - 143 */
+	99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,	/* 144 - 159 */
+	99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,	/* 160 - 175 */
+	99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,	/* 176 - 191 */
+	99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,	/* 192 - 207 */
+	99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,	/* 208 - 223 */
+	99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,	/* 224 - 239 */
+	99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,	/* 240 - 255 */
+};
+
+
+/**
+ * hex-encode
  *
  * @return 성공 시, CF_OK; 실패 시, 오류 코드
@@ -29,6 +80,5 @@
  *
  * @remark
- * 16진수 문자열을 저장할 메모리가 미리 할당되어야 하며, <br />
- * 크기는 null-character를 포함하여 len * 2 + 1
+ * hex는 할당된 메모리이며, 크기는 '\0'를 포함하여 len * 2 + 1
  */
 int
@@ -37,23 +87,23 @@
 					 char					* hex)
 {
-	size_t		iter = 0;
-	size_t		count = len * 2 + 1;
-
-	const char	hexchar[] = {'0', '1', '2', '3',
-							 '4', '5', '6', '7',
-							 '8', '9', 'a', 'b',
-							 'c', 'd', 'e', 'f'};
-
-	const __uchar	* ptr = bin;
+	size_t	iter = 0;
+	size_t	hexlen = len * 2 + 1;
+
+	const unsigned char	* ptr = bin;
+
+	const static char	hexchar[] = {'0', '1', '2', '3',
+									 '4', '5', '6', '7',
+									 '8', '9', 'a', 'b',
+									 'c', 'd', 'e', 'f'};
 
 	ASSERT_ARGS (bin == NULL);
 	ASSERT_ARGS (hex == NULL);
 
-	for (iter = 0 ; iter < count ; iter += 2, ptr++)
+	for (iter = 0 ; iter < hexlen ; iter += 2, ptr++)
 	{
 		hex[iter    ] = hexchar[((*(ptr)) >> 4) & 0x0f];
 		hex[iter + 1] = hexchar[((*(ptr))     ) & 0x0f];
 	}
-	hex[count - 1] = '\0';
+	hex[hexlen - 1] = '\0';
 
 	return CF_OK;
@@ -61,5 +111,5 @@
 
 /**
- * 16진수 문자열을 바이너리 데이터로 변환
+ * hex-decode
  *
  * @return 성공 시, CF_OK; 실패 시, 오류 코드
@@ -70,6 +120,5 @@
  *
  * @remark
- * 바이너리 데이터를 저장할 메모리가 미리 할당되어야 하며, <br />
- * 크기는 strlen (hex) / 2
+ * bin는 할당된 메모리이며, 크기는 strlen (hex) / 2
  */
 int
@@ -80,12 +129,12 @@
 	int		result = 0;
 
-	size_t	length = strlen (hex); /* absolutely even-number */
+	size_t	length = strlen (hex);	/* absolutely even-number */
 	size_t	iter = 0;
-	size_t	count = length / 2;
-	int		twochar = 0;
-
-	const char	* ptr = hex;
-	char		buf = 0;
-	__uchar		val = 0;
+	size_t	binlen = length / 2;
+
+	const char		* ptr = hex;
+	char			buf = 0;
+	unsigned char	val = 0;
+	unsigned char	asciiHex = 0;
 
 	ASSERT_ARGS (hex == NULL);
@@ -93,27 +142,161 @@
 	ASSERT_ARGS (len == NULL);
 
-	for (iter = 0 ; iter < count ; iter++)
-	{
-		for (twochar = 2, val = 0 ; twochar ; ptr++, twochar--)
-		{
-			buf = *ptr;
-			val = (__uchar)(val << 4);
-
-			if      (IS_NUMBER (buf))		val |= (__uchar)(buf - '0' +  0);
-			else if (IS_LOWERCASE (buf))	val |= (__uchar)(buf - 'a' + 10);
-			else if (IS_UPPERCASE (buf))	val |= (__uchar)(buf - 'A' + 10);
-			else
-			{
-				result = CF_ERROR_CODEC_NOT_HEXSTRING;
-				break;
-			}
-		}
+	for (iter = 0 ; iter < binlen ; iter++)
+	{
+		val = 0;	/* init/re-init docoding-buffer */
+
+		/* decode one character */
+#define DECODE_HEX(x)								\
+		do {										\
+		buf = *(x);									\
+		val = (unsigned char)(val << 4);			\
+		asciiHex = g_ascii_HexDecode[(int)buf];		\
+													\
+		if (buf)									\
+			val |=	(unsigned char)					\
+					(buf - asciiHex + (asciiHex == ASCN ? 0 : 10));	\
+		else										\
+			return CF_ERROR_CODEC_NOT_HEXSTRING;	\
+		} while (0)
+
+		/* decode one byte by decode two character */
+		DECODE_HEX (ptr++);
+		DECODE_HEX (ptr++);
 
 		bin[iter] = val;
 	}
 
-	if (result == 0)
-		*len = count;
+	*len = binlen;
 
 	return result;
 }
+
+/**
+ * Base64-encode
+ *
+ * @return 성공 시, CF_OK; 실패 시, 오류 코드
+ *
+ * @param bin		바이너리 데이터
+ * @param len		바이너리 데이터 길이
+ * @param base64	base64 문자열을 저장할 주소
+ *
+ * @remark
+ * base64는 할당된 메모리이며, 크기는 '\0'를 포함하여 (((len + 2) / 3) * 4) + 1
+ *
+ * @see http://sourceforge.net/p/predef/wiki/Endianness/
+ */
+int
+CF_Codec_Base64_Encode (const unsigned char	* bin,
+						const size_t		len,
+						char				* base64)
+{
+	size_t	iter = 0;
+	char	* ptr = base64;
+
+	ASSERT_ARGS (bin	== NULL);
+	ASSERT_ARGS (base64	== NULL);
+
+#define SEXTUPLE_E_1(__x,_idx)	((__x[_idx    ] >> 2) & 0x3f)
+#define SEXTUPLE_E_2(__x,_idx)	((__x[_idx    ] << 4) & 0x30)
+#define SEXTUPLE_E_3(__x,_idx)	((__x[_idx + 1] >> 4) & 0x0f)
+#define SEXTUPLE_E_4(__x,_idx)	((__x[_idx + 1] << 2) & 0x3c)
+#define SEXTUPLE_E_5(__x,_idx)	((__x[_idx + 2] >> 6) & 0x03)
+#define SEXTUPLE_E_6(__x,_idx)	((__x[_idx + 2]     ) & 0x3f)
+
+	for (iter = 0 ; iter < len - 2 ; iter += 3)
+	{
+		*ptr++ = g_table_Base64Encode[SEXTUPLE_E_1 (bin, iter)];
+		*ptr++ = g_table_Base64Encode[SEXTUPLE_E_2 (bin, iter)|
+									  SEXTUPLE_E_3 (bin, iter)];
+		*ptr++ = g_table_Base64Encode[SEXTUPLE_E_4 (bin, iter)|
+									  SEXTUPLE_E_5 (bin, iter)];
+		*ptr++ = g_table_Base64Encode[SEXTUPLE_E_6 (bin, iter)];
+	}
+
+	if (iter < len)
+	{
+		*ptr++ = g_table_Base64Encode[SEXTUPLE_E_1 (bin, iter)];
+
+		if (iter == (len - 1))
+		{
+			*ptr++ = g_table_Base64Encode[SEXTUPLE_E_2 (bin, iter)];
+			*ptr++ = g_table_Base64Encode[PADDING_CHAR_INDEX];
+		}
+		else
+		{
+			*ptr++ = g_table_Base64Encode[SEXTUPLE_E_2 (bin, iter)|
+										  SEXTUPLE_E_3 (bin, iter)];
+			*ptr++ = g_table_Base64Encode[SEXTUPLE_E_4 (bin, iter)];
+		}
+
+		*ptr++ = g_table_Base64Encode[PADDING_CHAR_INDEX];
+	}
+	*ptr = '\0';
+
+	return CF_OK;
+}
+
+/**
+ * Base64-decode
+ *
+ * @return 성공 시, CF_OK; 실패 시, 오류 코드
+ *
+ * @param base64	base64 문자열
+ * @param bin		바이너리 데이터를 저장할 주소
+ * @param len		바이너리 데이터의 길이를 저장할 주소
+ *
+ * @remark
+ * base64는 할당된 메모리이며, 크기는 (strlen (base64) - <'=' 개수>) / 4 * 3
+ *
+ * @see http://sourceforge.net/p/predef/wiki/Endianness/
+ */
+int
+CF_Codec_Base64_Decode (const char		* base64,
+						unsigned char	* bin,
+						size_t			* len)
+{
+	size_t			remain = 0;
+	const char		* src = base64;
+	unsigned char	* dst = bin;
+	size_t			binlen = 0;
+
+	ASSERT_ARGS (base64	== NULL);
+	ASSERT_ARGS (bin	== NULL);
+	ASSERT_ARGS (len	== NULL);
+
+	while (*src && g_ascii_Base64Decode[(int)*src] < PADDING_CHAR_INDEX) src++;
+
+	if (*src)
+		return CF_ERROR_CODEC_NOT_BASE64;
+
+	remain = (size_t)(src - base64);
+	binlen = ((remain + 3) / 4) * 3;
+
+#define SEXTUPLE_D_1(src)	(g_ascii_Base64Decode[(int)src[0]] << 2)
+#define SEXTUPLE_D_2(src)	(g_ascii_Base64Decode[(int)src[1]] >> 4)
+#define SEXTUPLE_D_3(src)	(g_ascii_Base64Decode[(int)src[1]] << 4)
+#define SEXTUPLE_D_4(src)	(g_ascii_Base64Decode[(int)src[2]] >> 2)
+#define SEXTUPLE_D_5(src)	(g_ascii_Base64Decode[(int)src[2]] << 6)
+#define SEXTUPLE_D_6(src)	(g_ascii_Base64Decode[(int)src[3]]     )
+
+	for (src = base64, dst = bin ; remain > 4 ; remain -= 4, src += 4)
+	{
+		*dst++ = (unsigned char)(SEXTUPLE_D_1 (src) | SEXTUPLE_D_2 (src));
+		*dst++ = (unsigned char)(SEXTUPLE_D_3 (src) | SEXTUPLE_D_4 (src));
+		*dst++ = (unsigned char)(SEXTUPLE_D_5 (src) | SEXTUPLE_D_6 (src));
+	}
+
+	if (remain > 1)
+		*dst++ = (unsigned char)(SEXTUPLE_D_1 (src) | SEXTUPLE_D_2 (src));
+
+	if (remain > 2)
+		*dst++ = (unsigned char)(SEXTUPLE_D_3 (src) | SEXTUPLE_D_4 (src));
+
+	if (remain > 3)
+		*dst++ = (unsigned char)(SEXTUPLE_D_5 (src) | SEXTUPLE_D_6 (src));
+
+	*dst++ = '\0';
+	*len = binlen;
+
+	return CF_OK;
+}
Index: /trunk/test/codec.c
===================================================================
--- /trunk/test/codec.c	(revision 87)
+++ /trunk/test/codec.c	(revision 88)
@@ -12,16 +12,33 @@
 	char data[] = "ONE OK ROCK - Nothing Helps";
 
-	char hex[512] = {0x00,};
+	char encode[512] = {0x00,};
 	unsigned char bin[512] = {0x00,};
 	size_t length = 0;
 
+	/* hex */
+	CF_DEBUG_PRINT (stderr, "------------------- codec/hex ----------------\n");
 	CF_DEBUG_PRINT (stderr, "data   : %s\n", data);
 	CF_DEBUG_PRINT (stderr, "= Convert binary to hex =\n");
-	CF_Codec_Hex_Encode ((unsigned char *)data, strlen (data), hex);
-	CF_DEBUG_PRINT (stderr, "hex    : %s\n", hex);
+	CF_Codec_Hex_Encode ((unsigned char *)data, strlen (data), encode);
+	CF_DEBUG_PRINT (stderr, "hex    : %s\n", encode);
 	CF_DEBUG_PRINT_BIN (stderr, (unsigned char *) data, strlen (data), "data   : %s\n", data);
 
 	CF_DEBUG_PRINT (stderr, "= Convert hex to binary =\n");
-	CF_Codec_Hex_Decode (hex, bin, &length);
+	CF_Codec_Hex_Decode (encode, bin, &length);
+	CF_DEBUG_PRINT_BIN (stderr, bin, length, "bin    : %s\n", bin);
+
+	memset (bin   , 0x00, sizeof (bin));
+	memset (encode, 0x00, sizeof (encode));
+	length = 0;
+
+	/* base64 */
+	CF_DEBUG_PRINT (stderr, "----------------- codec/base64 ---------------\n");
+	CF_DEBUG_PRINT (stderr, "data   : %s\n", data);
+	CF_DEBUG_PRINT (stderr, "= Convert binary to base64 =\n");
+	CF_Codec_Base64_Encode ((unsigned char *)data, strlen (data), encode);
+	CF_DEBUG_PRINT (stderr, "base64 : %s\n", encode);
+
+	CF_DEBUG_PRINT (stderr, "= Convert base64 to binary =\n");
+	CF_Codec_Base64_Decode (encode, bin, &length);
 	CF_DEBUG_PRINT_BIN (stderr, bin, length, "bin    : %s\n", bin);
 
Index: /trunk/test/test.c
===================================================================
--- /trunk/test/test.c	(revision 87)
+++ /trunk/test/test.c	(revision 88)
@@ -387,16 +387,33 @@
 	char data[] = "ONE OK ROCK - Nothing Helps";
 
-	char hex[512] = {0x00,};
+	char encode[512] = {0x00,};
 	unsigned char bin[512] = {0x00,};
 	size_t length = 0;
 
+	/* hex */
+	CF_DEBUG_PRINT (stderr, "------------------- codec/hex ----------------\n");
 	CF_DEBUG_PRINT (stderr, "data   : %s\n", data);
 	CF_DEBUG_PRINT (stderr, "= Convert binary to hex =\n");
-	CF_Codec_Hex_Encode ((unsigned char *)data, strlen (data), hex);
-	CF_DEBUG_PRINT (stderr, "hex    : %s\n", hex);
+	CF_Codec_Hex_Encode ((unsigned char *)data, strlen (data), encode);
+	CF_DEBUG_PRINT (stderr, "hex    : %s\n", encode);
 	CF_DEBUG_PRINT_BIN (stderr, (unsigned char *) data, strlen (data), "data   : %s\n", data);
 
 	CF_DEBUG_PRINT (stderr, "= Convert hex to binary =\n");
-	CF_Codec_Hex_Decode (hex, bin, &length);
+	CF_Codec_Hex_Decode (encode, bin, &length);
 	CF_DEBUG_PRINT_BIN (stderr, bin, length, "bin    : %s\n", bin);
-}
+
+	memset (bin   , 0x00, sizeof (bin));
+	memset (encode, 0x00, sizeof (encode));
+	length = 0;
+
+	/* base64 */
+	CF_DEBUG_PRINT (stderr, "----------------- codec/base64 ---------------\n");
+	CF_DEBUG_PRINT (stderr, "data   : %s\n", data);
+	CF_DEBUG_PRINT (stderr, "= Convert binary to base64 =\n");
+	CF_Codec_Base64_Encode ((unsigned char *)data, strlen (data), encode);
+	CF_DEBUG_PRINT (stderr, "base64 : %s\n", encode);
+
+	CF_DEBUG_PRINT (stderr, "= Convert base64 to binary =\n");
+	CF_Codec_Base64_Decode (encode, bin, &length);
+	CF_DEBUG_PRINT_BIN (stderr, bin, length, "bin    : %s\n", bin);
+}
