/** * @file codec.cpp * @author myusgun@gmail.com * @brief codec */ #include "cf/codec.h" #include "cf/memory.h" #define BASE64_PADDING_CHAR_INDEX 64 cf::codec::base64 * cf::codec::base64::getInstance() { static cf::codec::base64 instance; return &instance; } std::string cf::codec::base64::encode(const cf::bin & in) const throw (cf::exception) { if (in.empty()) THROW_EXCEPTION("input is empty"); try { cf::size_t inlen = in.size(); cf::char_t * buf = NULL; cf::size_t memsize = (((inlen + 2) / 3) * 4) + 1; cf::memory mem(memsize); buf = reinterpret_cast(mem.buffer()); /*--------------------------------------------------------------*/ cf::char_t * dst = buf; const cf::uint8_t * src = in.buffer(); const cf::uint8_t * ptr = src; const static cf::char_t base64enc[] = { '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 */ }; #define SEXTUPLE_E_1(__x) (((__x[0]) >> 2) & 0x3f) #define SEXTUPLE_E_2(__x) (((__x[0]) << 4) & 0x30) #define SEXTUPLE_E_3(__x) (((__x[1]) >> 4) & 0x0f) #define SEXTUPLE_E_4(__x) (((__x[1]) << 2) & 0x3c) #define SEXTUPLE_E_5(__x) (((__x[2]) >> 6) & 0x03) #define SEXTUPLE_E_6(__x) (((__x[2]) ) & 0x3f) for ( ; static_cast(ptr - src) < (inlen - 2) ; ptr += 3) { *dst++ = base64enc[SEXTUPLE_E_1 (ptr)]; *dst++ = base64enc[SEXTUPLE_E_2 (ptr) | SEXTUPLE_E_3 (ptr)]; *dst++ = base64enc[SEXTUPLE_E_4 (ptr) | SEXTUPLE_E_5 (ptr)]; *dst++ = base64enc[SEXTUPLE_E_6 (ptr)]; } if (static_cast(ptr - src) < inlen) { *dst++ = base64enc[SEXTUPLE_E_1 (ptr)]; if (static_cast(ptr - src) == (inlen - 1)) { *dst++ = base64enc[SEXTUPLE_E_2 (ptr)]; *dst++ = base64enc[BASE64_PADDING_CHAR_INDEX]; } else { *dst++ = base64enc[SEXTUPLE_E_2 (ptr) | SEXTUPLE_E_3 (ptr)]; *dst++ = base64enc[SEXTUPLE_E_4 (ptr)]; } *dst++ = base64enc[BASE64_PADDING_CHAR_INDEX]; } *dst = '\0'; /*--------------------------------------------------------------*/ return std::string(buf); } catch (cf::exception &e) { FORWARD_EXCEPTION(e); } } cf::bin cf::codec::base64::decode(const std::string & in) const throw (cf::exception) { if (in.empty()) THROW_EXCEPTION("base64 string is empty"); try { cf::uint8_t * buf = NULL; cf::long_t outlen = 0; cf::size_t memsize = in.size() / 4 * 3; cf::memory mem(memsize); buf = reinterpret_cast(mem.buffer()); /*--------------------------------------------------------------*/ const cf::char_t * src = in.c_str(); const cf::char_t * ptr = src; cf::uint8_t * dst = buf; cf::long_t remain = 0; cf::long_t binlen = 0; const static cf::uint8_t base64dec[] = { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 00 - 07 */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 08 - 15 */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 16 - 23 */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 24 - 31 */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 32 - 39 */ 0xff,0xff,0xff, 62,0xff,0xff,0xff, 63, /* 40 - 47 */ 52, 53, 54, 55, 56, 57, 58, 59, /* 48 - 55 */ 60, 61,0xff,0xff,0xff, 64,0xff,0xff, /* 56 - 63 */ 0xff, 0, 1, 2, 3, 4, 5, 6, /* 64 - 71 */ 7, 8, 9, 10, 11, 12, 13, 14, /* 71 - 79 */ 15, 16, 17, 18, 19, 20, 21, 22, /* 80 - 87 */ 23, 24, 25,0xff,0xff,0xff,0xff,0xff, /* 88 - 95 */ 0xff, 26, 27, 28, 29, 30, 31, 32, /* 96 - 103 */ 33, 34, 35, 36, 37, 38, 39, 40, /* 104 - 111 */ 41, 42, 43, 44, 45, 46, 47, 48, /* 112 - 119 */ 49, 50, 51,0xff,0xff,0xff,0xff,0xff /* 120 - 127 */ }; while (base64dec[(int)*ptr] < BASE64_PADDING_CHAR_INDEX) ptr++; if (*ptr == 0xff) THROW_EXCEPTION("input string is not base64-encoded"); remain = ptr - src; binlen = ((remain + 2/* max padding length */) / 4) * 3; #define SEXTUPLE_D_1(src) (base64dec[(int)src[0]] << 2) #define SEXTUPLE_D_2(src) (base64dec[(int)src[1]] >> 4) #define SEXTUPLE_D_3(src) (base64dec[(int)src[1]] << 4) #define SEXTUPLE_D_4(src) (base64dec[(int)src[2]] >> 2) #define SEXTUPLE_D_5(src) (base64dec[(int)src[2]] << 6) #define SEXTUPLE_D_6(src) (base64dec[(int)src[3]] ) for (ptr = src ; remain > 4 ; remain -= 4, ptr += 4) { *dst++ = (cf::uint8_t)(SEXTUPLE_D_1(ptr) | SEXTUPLE_D_2(ptr)); *dst++ = (cf::uint8_t)(SEXTUPLE_D_3(ptr) | SEXTUPLE_D_4(ptr)); *dst++ = (cf::uint8_t)(SEXTUPLE_D_5(ptr) | SEXTUPLE_D_6(ptr)); } if (remain > 1) *dst++ = (cf::uint8_t)(SEXTUPLE_D_1(ptr) | SEXTUPLE_D_2(ptr)); if (remain > 2) *dst++ = (cf::uint8_t)(SEXTUPLE_D_3(ptr) | SEXTUPLE_D_4(ptr)); if (remain > 3) *dst++ = (cf::uint8_t)(SEXTUPLE_D_5(ptr) | SEXTUPLE_D_6(ptr)); outlen = binlen - (4 - remain); /*--------------------------------------------------------------*/ return cf::bin(buf, static_cast(outlen)); } catch (cf::exception &e) { FORWARD_EXCEPTION(e); } } cf::codec::hex * cf::codec::hex::getInstance() { static cf::codec::hex instance; return &instance; } std::string cf::codec::hex::encode(const cf::bin & in) const throw (cf::exception) { if (in.empty()) THROW_EXCEPTION("input is empty"); try { cf::char_t * buf = NULL; cf::size_t memsize = in.size() * 2 + 1; cf::memory mem(memsize); buf = reinterpret_cast(mem.buffer()); /*--------------------------------------------------------------*/ const cf::uint8_t * src = in.buffer(); cf::char_t * dst = buf; const static cf::char_t hexenc[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; for ( ; static_cast(src - in.buffer()) < in.size() ; src++) { *dst++ = hexenc[((*src) >> 4) & 0x0f]; *dst++ = hexenc[((*src) ) & 0x0f]; } *dst = '\0'; /*--------------------------------------------------------------*/ return std::string(buf); } catch (cf::exception &e) { FORWARD_EXCEPTION(e); } } cf::bin cf::codec::hex::decode(const std::string & in) const throw (cf::exception) { if (in.empty()) THROW_EXCEPTION("hex string is empty"); try { cf::uint8_t * buf = NULL; cf::int32_t len = 0; cf::size_t memsize = in.size() / 2; cf::memory mem(memsize); buf = reinterpret_cast(mem.buffer()); /*--------------------------------------------------------------*/ cf::int32_t length = 0; /* even-number */ const cf::char_t * src = in.c_str(); const cf::char_t * ptr = src; cf::uint8_t * dst = buf; cf::uint8_t val = 0; cf::uint8_t sum = 0; cf::uint8_t asciiHex = 0; const static cf::uint8_t hexdec[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00 - 07 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 08 - 15 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16 - 23 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24 - 31 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 32 - 39 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 40 - 47 */ '0', '0', '0', '0', '0', '0', '0', '0', /* 48 - 55 */ '0', '0',0x00,0x00,0x00,0x00,0x00,0x00, /* 56 - 63 */ 0x00, 'A', 'A', 'A', 'A', 'A', 'A',0x00, /* 64 - 71 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 71 - 79 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 80 - 87 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 88 - 95 */ 0x00, 'a', 'a', 'a', 'a', 'a', 'a',0x00, /* 96 - 103 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 104 - 111 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 112 - 119 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 /* 120 - 127 */ }; for ( ; hexdec[(int)*ptr] && *ptr ; ptr++, length++); if (*ptr) THROW_EXCEPTION("input string is not hex-encoded"); for (ptr = src ; *ptr ; ) { sum = 0; /* init/re-init decoding-buffer */ /* decode one character */ #define DECODE_HEX(x) \ do { \ val = static_cast(*(x)); \ sum = (cf::uint8_t)(sum << 4); \ asciiHex = hexdec[val]; \ \ sum |= (cf::uint8_t) \ (val - asciiHex + (asciiHex == '0' ? 0 : 10)); \ } while (0) /* decode one byte by decode two character */ DECODE_HEX(ptr++); DECODE_HEX(ptr++); *dst++ = sum; } len = length / 2; /*--------------------------------------------------------------*/ return cf::bin(buf, len); } catch (cf::exception &e) { FORWARD_EXCEPTION(e); } }