Changeset 88 in libcf


Ignore:
Timestamp:
05/17/13 02:17:16 (11 years ago)
Author:
cheese
Message:

#1 add base64 and arrange hex-decoding more fast

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/cf_codec.h

    r86 r88  
    77 * @example codec.c
    88 */
     9#ifndef __CF_CODEC_H__
     10#define __CF_CODEC_H__
     11
    912#include "cf_base.h"
    1013
    1114#include <stddef.h>
    12 
    13 #ifndef __CF_CODEC_H__
    14 #define __CF_CODEC_H__
    1515
    1616#ifdef __cplusplus
     
    1919
    2020CF_EXPORT int
    21 CF_Codec_Hex_Encode     (const unsigned char    * bin,
    22                         const size_t           len,
    23                         char                   * hex);
     21CF_Codec_Hex_Encode         (const unsigned char    * bin,
     22                            const size_t           len,
     23                            char                   * hex);
    2424
    2525CF_EXPORT int
    26 CF_Codec_Hex_Decode     (const char     * hex,
    27                          unsigned char  * bin,
    28                          size_t         * len);
     26CF_Codec_Hex_Decode         (const char     * hex,
     27                             unsigned char  * bin,
     28                             size_t         * len);
     29
     30CF_EXPORT int
     31CF_Codec_Base64_Encode      (const unsigned char    * bin,
     32                             const size_t           len,
     33                             char                   * base64);
     34
     35CF_EXPORT int
     36CF_Codec_Base64_Decode      (const char     * base64,
     37                             unsigned char  * bin,
     38                             size_t         * len);
    2939
    3040#ifdef __cplusplus
  • trunk/include/cf_error.h

    r80 r88  
    104104#define CF_ERROR_CODEC_INVALID_ARGS         CF_ERROR_CODEC - 1
    105105#define CF_ERROR_CODEC_NOT_HEXSTRING        CF_ERROR_CODEC - 2
     106#define CF_ERROR_CODEC_NOT_BASE64           CF_ERROR_CODEC - 3
    106107/* }}} codec */
    107108
  • trunk/src/cf_codec.c

    r86 r88  
    1313        return CF_ERROR_CODEC_INVALID_ARGS
    1414
    15 #define IS_NUMBER(x)        (x >= '0' && x <= '9')
    16 #define IS_LOWERCASE(x)     (x >= 'a' && x <= 'f')
    17 #define IS_UPPERCASE(x)     (x >= 'A' && x <= 'F')
    18 
    19 typedef unsigned char __uchar;
    20 
    21 /**
    22  * 바이너리 데이터를 16진수 문자열로 변환
     15const static unsigned char g_ascii_HexDecode[] = {
     16#define ASCN    '0' /* ascii number */
     17#define ASCU    'A' /* ascii upper */
     18#define ASCL    'a' /* ascii lower */
     19    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,    /*  00 -  15 */
     20    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,    /*  16 -  31 */
     21    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,    /*  32 -  47 */
     22    ASCN,ASCN,ASCN,ASCN,ASCN,ASCN,ASCN,ASCN,ASCN,ASCN,0x00,0x00,0x00,0x00,0x00,0x00,    /*  48 -  63 */
     23    0x00,ASCU,ASCU,ASCU,ASCU,ASCU,ASCU,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,    /*  64 -  79 */
     24    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,    /*  80 -  95 */
     25    0x00,ASCL,ASCL,ASCL,ASCL,ASCL,ASCL,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,    /*  96 - 111 */
     26    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,    /* 112 - 127 */
     27    /* end of ascii character */
     28    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,    /* 128 - 143 */
     29    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,    /* 144 - 159 */
     30    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,    /* 160 - 175 */
     31    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,    /* 176 - 191 */
     32    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,    /* 192 - 207 */
     33    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,    /* 208 - 223 */
     34    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,    /* 224 - 239 */
     35    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,    /* 240 - 255 */
     36};
     37
     38const static char g_table_Base64Encode[] = {
     39#define PADDING_CHAR_INDEX  64
     40    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',     /* 00 - 07 */
     41    'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',     /* 08 - 15 */
     42    'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',     /* 16 - 23 */
     43    'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',     /* 24 - 31 */
     44    'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',     /* 32 - 39 */
     45    'o', 'p', 'q', 'r', 's', 't', 'u', 'v',     /* 40 - 47 */
     46    'w', 'x', 'y', 'z', '0', '1', '2', '3',     /* 48 - 55 */
     47    '4', '5', '6', '7', '8', '9', '+', '/',     /* 56 - 63 */
     48    '='                                         /* padding */
     49};
     50
     51const static unsigned char g_ascii_Base64Decode[] = {
     52    99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,    /*  00 -  15 */
     53    99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,    /*  16 -  31 */
     54    99,99,99,99,99,99,99,99,99,99,99,62,99,99,99,63,    /*  32 -  47 */
     55    52,53,54,55,56,57,58,59,60,61,99,99,99,64,99,99,    /*  48 -  63 */
     56    99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,    /*  64 -  79 */
     57    15,16,17,18,19,20,21,22,23,24,25,99,99,99,99,99,    /*  80 -  95 */
     58    99,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,    /*  96 - 111 */
     59    41,42,43,44,45,46,47,48,49,50,51,99,99,99,99,99,    /* 112 - 127 */
     60    /* end of ascii character */
     61    99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,    /* 128 - 143 */
     62    99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,    /* 144 - 159 */
     63    99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,    /* 160 - 175 */
     64    99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,    /* 176 - 191 */
     65    99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,    /* 192 - 207 */
     66    99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,    /* 208 - 223 */
     67    99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,    /* 224 - 239 */
     68    99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,    /* 240 - 255 */
     69};
     70
     71
     72/**
     73 * hex-encode
    2374 *
    2475 * @return 성공 시, CF_OK; 실패 시, 오류 코드
     
    2980 *
    3081 * @remark
    31  * 16진수 문자열을 저장할 메모리가 미리 할당되어야 하며, <br />
    32  * 크기는 null-character를 포함하여 len * 2 + 1
     82 * hex는 할당된 메모리이며, 크기는 '\0'를 포함하여 len * 2 + 1
    3383 */
    3484int
     
    3787                     char                   * hex)
    3888{
    39     size_t      iter = 0;
    40     size_t      count = len * 2 + 1;
    41 
    42     const char  hexchar[] = {'0', '1', '2', '3',
    43                              '4', '5', '6', '7',
    44                              '8', '9', 'a', 'b',
    45                              'c', 'd', 'e', 'f'};
    46 
    47     const __uchar   * ptr = bin;
     89    size_t  iter = 0;
     90    size_t  hexlen = len * 2 + 1;
     91
     92    const unsigned char * ptr = bin;
     93
     94    const static char   hexchar[] = {'0', '1', '2', '3',
     95                                     '4', '5', '6', '7',
     96                                     '8', '9', 'a', 'b',
     97                                     'c', 'd', 'e', 'f'};
    4898
    4999    ASSERT_ARGS (bin == NULL);
    50100    ASSERT_ARGS (hex == NULL);
    51101
    52     for (iter = 0 ; iter < count ; iter += 2, ptr++)
     102    for (iter = 0 ; iter < hexlen ; iter += 2, ptr++)
    53103    {
    54104        hex[iter    ] = hexchar[((*(ptr)) >> 4) & 0x0f];
    55105        hex[iter + 1] = hexchar[((*(ptr))     ) & 0x0f];
    56106    }
    57     hex[count - 1] = '\0';
     107    hex[hexlen - 1] = '\0';
    58108
    59109    return CF_OK;
     
    61111
    62112/**
    63  * 16진수 문자열을 바이너리 데이터로 변환
     113 * hex-decode
    64114 *
    65115 * @return 성공 시, CF_OK; 실패 시, 오류 코드
     
    70120 *
    71121 * @remark
    72  * 바이너리 데이터를 저장할 메모리가 미리 할당되어야 하며, <br />
    73  * 크기는 strlen (hex) / 2
     122 * bin는 할당된 메모리이며, 크기는 strlen (hex) / 2
    74123 */
    75124int
     
    80129    int     result = 0;
    81130
    82     size_t  length = strlen (hex); /* absolutely even-number */
     131    size_t  length = strlen (hex);  /* absolutely even-number */
    83132    size_t  iter = 0;
    84     size_t  count = length / 2;
    85     int     twochar = 0;
    86 
    87     const char  * ptr = hex;
    88     char        buf = 0;
    89     __uchar     val = 0;
     133    size_t  binlen = length / 2;
     134
     135    const char      * ptr = hex;
     136    char            buf = 0;
     137    unsigned char   val = 0;
     138    unsigned char   asciiHex = 0;
    90139
    91140    ASSERT_ARGS (hex == NULL);
     
    93142    ASSERT_ARGS (len == NULL);
    94143
    95     for (iter = 0 ; iter < count ; iter++)
    96     {
    97         for (twochar = 2, val = 0 ; twochar ; ptr++, twochar--)
    98         {
    99             buf = *ptr;
    100             val = (__uchar)(val << 4);
    101 
    102             if      (IS_NUMBER (buf))       val |= (__uchar)(buf - '0' +  0);
    103             else if (IS_LOWERCASE (buf))    val |= (__uchar)(buf - 'a' + 10);
    104             else if (IS_UPPERCASE (buf))    val |= (__uchar)(buf - 'A' + 10);
    105             else
    106             {
    107                 result = CF_ERROR_CODEC_NOT_HEXSTRING;
    108                 break;
    109             }
    110         }
     144    for (iter = 0 ; iter < binlen ; iter++)
     145    {
     146        val = 0;    /* init/re-init docoding-buffer */
     147
     148        /* decode one character */
     149#define DECODE_HEX(x)                               \
     150        do {                                        \
     151        buf = *(x);                                 \
     152        val = (unsigned char)(val << 4);            \
     153        asciiHex = g_ascii_HexDecode[(int)buf];     \
     154                                                    \
     155        if (buf)                                    \
     156            val |=  (unsigned char)                 \
     157                    (buf - asciiHex + (asciiHex == ASCN ? 0 : 10)); \
     158        else                                        \
     159            return CF_ERROR_CODEC_NOT_HEXSTRING;    \
     160        } while (0)
     161
     162        /* decode one byte by decode two character */
     163        DECODE_HEX (ptr++);
     164        DECODE_HEX (ptr++);
    111165
    112166        bin[iter] = val;
    113167    }
    114168
    115     if (result == 0)
    116         *len = count;
     169    *len = binlen;
    117170
    118171    return result;
    119172}
     173
     174/**
     175 * Base64-encode
     176 *
     177 * @return 성공 시, CF_OK; 실패 시, 오류 코드
     178 *
     179 * @param bin       바이너리 데이터
     180 * @param len       바이너리 데이터 길이
     181 * @param base64    base64 문자열을 저장할 주소
     182 *
     183 * @remark
     184 * base64는 할당된 메모리이며, 크기는 '\0'를 포함하여 (((len + 2) / 3) * 4) + 1
     185 *
     186 * @see http://sourceforge.net/p/predef/wiki/Endianness/
     187 */
     188int
     189CF_Codec_Base64_Encode (const unsigned char * bin,
     190                        const size_t        len,
     191                        char                * base64)
     192{
     193    size_t  iter = 0;
     194    char    * ptr = base64;
     195
     196    ASSERT_ARGS (bin    == NULL);
     197    ASSERT_ARGS (base64 == NULL);
     198
     199#define SEXTUPLE_E_1(__x,_idx)  ((__x[_idx    ] >> 2) & 0x3f)
     200#define SEXTUPLE_E_2(__x,_idx)  ((__x[_idx    ] << 4) & 0x30)
     201#define SEXTUPLE_E_3(__x,_idx)  ((__x[_idx + 1] >> 4) & 0x0f)
     202#define SEXTUPLE_E_4(__x,_idx)  ((__x[_idx + 1] << 2) & 0x3c)
     203#define SEXTUPLE_E_5(__x,_idx)  ((__x[_idx + 2] >> 6) & 0x03)
     204#define SEXTUPLE_E_6(__x,_idx)  ((__x[_idx + 2]     ) & 0x3f)
     205
     206    for (iter = 0 ; iter < len - 2 ; iter += 3)
     207    {
     208        *ptr++ = g_table_Base64Encode[SEXTUPLE_E_1 (bin, iter)];
     209        *ptr++ = g_table_Base64Encode[SEXTUPLE_E_2 (bin, iter)|
     210                                      SEXTUPLE_E_3 (bin, iter)];
     211        *ptr++ = g_table_Base64Encode[SEXTUPLE_E_4 (bin, iter)|
     212                                      SEXTUPLE_E_5 (bin, iter)];
     213        *ptr++ = g_table_Base64Encode[SEXTUPLE_E_6 (bin, iter)];
     214    }
     215
     216    if (iter < len)
     217    {
     218        *ptr++ = g_table_Base64Encode[SEXTUPLE_E_1 (bin, iter)];
     219
     220        if (iter == (len - 1))
     221        {
     222            *ptr++ = g_table_Base64Encode[SEXTUPLE_E_2 (bin, iter)];
     223            *ptr++ = g_table_Base64Encode[PADDING_CHAR_INDEX];
     224        }
     225        else
     226        {
     227            *ptr++ = g_table_Base64Encode[SEXTUPLE_E_2 (bin, iter)|
     228                                          SEXTUPLE_E_3 (bin, iter)];
     229            *ptr++ = g_table_Base64Encode[SEXTUPLE_E_4 (bin, iter)];
     230        }
     231
     232        *ptr++ = g_table_Base64Encode[PADDING_CHAR_INDEX];
     233    }
     234    *ptr = '\0';
     235
     236    return CF_OK;
     237}
     238
     239/**
     240 * Base64-decode
     241 *
     242 * @return 성공 시, CF_OK; 실패 시, 오류 코드
     243 *
     244 * @param base64    base64 문자열
     245 * @param bin       바이너리 데이터를 저장할 주소
     246 * @param len       바이너리 데이터의 길이를 저장할 주소
     247 *
     248 * @remark
     249 * base64는 할당된 메모리이며, 크기는 (strlen (base64) - <'=' 개수>) / 4 * 3
     250 *
     251 * @see http://sourceforge.net/p/predef/wiki/Endianness/
     252 */
     253int
     254CF_Codec_Base64_Decode (const char      * base64,
     255                        unsigned char   * bin,
     256                        size_t          * len)
     257{
     258    size_t          remain = 0;
     259    const char      * src = base64;
     260    unsigned char   * dst = bin;
     261    size_t          binlen = 0;
     262
     263    ASSERT_ARGS (base64 == NULL);
     264    ASSERT_ARGS (bin    == NULL);
     265    ASSERT_ARGS (len    == NULL);
     266
     267    while (*src && g_ascii_Base64Decode[(int)*src] < PADDING_CHAR_INDEX) src++;
     268
     269    if (*src)
     270        return CF_ERROR_CODEC_NOT_BASE64;
     271
     272    remain = (size_t)(src - base64);
     273    binlen = ((remain + 3) / 4) * 3;
     274
     275#define SEXTUPLE_D_1(src)   (g_ascii_Base64Decode[(int)src[0]] << 2)
     276#define SEXTUPLE_D_2(src)   (g_ascii_Base64Decode[(int)src[1]] >> 4)
     277#define SEXTUPLE_D_3(src)   (g_ascii_Base64Decode[(int)src[1]] << 4)
     278#define SEXTUPLE_D_4(src)   (g_ascii_Base64Decode[(int)src[2]] >> 2)
     279#define SEXTUPLE_D_5(src)   (g_ascii_Base64Decode[(int)src[2]] << 6)
     280#define SEXTUPLE_D_6(src)   (g_ascii_Base64Decode[(int)src[3]]     )
     281
     282    for (src = base64, dst = bin ; remain > 4 ; remain -= 4, src += 4)
     283    {
     284        *dst++ = (unsigned char)(SEXTUPLE_D_1 (src) | SEXTUPLE_D_2 (src));
     285        *dst++ = (unsigned char)(SEXTUPLE_D_3 (src) | SEXTUPLE_D_4 (src));
     286        *dst++ = (unsigned char)(SEXTUPLE_D_5 (src) | SEXTUPLE_D_6 (src));
     287    }
     288
     289    if (remain > 1)
     290        *dst++ = (unsigned char)(SEXTUPLE_D_1 (src) | SEXTUPLE_D_2 (src));
     291
     292    if (remain > 2)
     293        *dst++ = (unsigned char)(SEXTUPLE_D_3 (src) | SEXTUPLE_D_4 (src));
     294
     295    if (remain > 3)
     296        *dst++ = (unsigned char)(SEXTUPLE_D_5 (src) | SEXTUPLE_D_6 (src));
     297
     298    *dst++ = '\0';
     299    *len = binlen;
     300
     301    return CF_OK;
     302}
  • trunk/test/codec.c

    r86 r88  
    1212    char data[] = "ONE OK ROCK - Nothing Helps";
    1313
    14     char hex[512] = {0x00,};
     14    char encode[512] = {0x00,};
    1515    unsigned char bin[512] = {0x00,};
    1616    size_t length = 0;
    1717
     18    /* hex */
     19    CF_DEBUG_PRINT (stderr, "------------------- codec/hex ----------------\n");
    1820    CF_DEBUG_PRINT (stderr, "data   : %s\n", data);
    1921    CF_DEBUG_PRINT (stderr, "= Convert binary to hex =\n");
    20     CF_Codec_Hex_Encode ((unsigned char *)data, strlen (data), hex);
    21     CF_DEBUG_PRINT (stderr, "hex    : %s\n", hex);
     22    CF_Codec_Hex_Encode ((unsigned char *)data, strlen (data), encode);
     23    CF_DEBUG_PRINT (stderr, "hex    : %s\n", encode);
    2224    CF_DEBUG_PRINT_BIN (stderr, (unsigned char *) data, strlen (data), "data   : %s\n", data);
    2325
    2426    CF_DEBUG_PRINT (stderr, "= Convert hex to binary =\n");
    25     CF_Codec_Hex_Decode (hex, bin, &length);
     27    CF_Codec_Hex_Decode (encode, bin, &length);
     28    CF_DEBUG_PRINT_BIN (stderr, bin, length, "bin    : %s\n", bin);
     29
     30    memset (bin   , 0x00, sizeof (bin));
     31    memset (encode, 0x00, sizeof (encode));
     32    length = 0;
     33
     34    /* base64 */
     35    CF_DEBUG_PRINT (stderr, "----------------- codec/base64 ---------------\n");
     36    CF_DEBUG_PRINT (stderr, "data   : %s\n", data);
     37    CF_DEBUG_PRINT (stderr, "= Convert binary to base64 =\n");
     38    CF_Codec_Base64_Encode ((unsigned char *)data, strlen (data), encode);
     39    CF_DEBUG_PRINT (stderr, "base64 : %s\n", encode);
     40
     41    CF_DEBUG_PRINT (stderr, "= Convert base64 to binary =\n");
     42    CF_Codec_Base64_Decode (encode, bin, &length);
    2643    CF_DEBUG_PRINT_BIN (stderr, bin, length, "bin    : %s\n", bin);
    2744
  • trunk/test/test.c

    r86 r88  
    387387    char data[] = "ONE OK ROCK - Nothing Helps";
    388388
    389     char hex[512] = {0x00,};
     389    char encode[512] = {0x00,};
    390390    unsigned char bin[512] = {0x00,};
    391391    size_t length = 0;
    392392
     393    /* hex */
     394    CF_DEBUG_PRINT (stderr, "------------------- codec/hex ----------------\n");
    393395    CF_DEBUG_PRINT (stderr, "data   : %s\n", data);
    394396    CF_DEBUG_PRINT (stderr, "= Convert binary to hex =\n");
    395     CF_Codec_Hex_Encode ((unsigned char *)data, strlen (data), hex);
    396     CF_DEBUG_PRINT (stderr, "hex    : %s\n", hex);
     397    CF_Codec_Hex_Encode ((unsigned char *)data, strlen (data), encode);
     398    CF_DEBUG_PRINT (stderr, "hex    : %s\n", encode);
    397399    CF_DEBUG_PRINT_BIN (stderr, (unsigned char *) data, strlen (data), "data   : %s\n", data);
    398400
    399401    CF_DEBUG_PRINT (stderr, "= Convert hex to binary =\n");
    400     CF_Codec_Hex_Decode (hex, bin, &length);
     402    CF_Codec_Hex_Decode (encode, bin, &length);
    401403    CF_DEBUG_PRINT_BIN (stderr, bin, length, "bin    : %s\n", bin);
    402 }
     404
     405    memset (bin   , 0x00, sizeof (bin));
     406    memset (encode, 0x00, sizeof (encode));
     407    length = 0;
     408
     409    /* base64 */
     410    CF_DEBUG_PRINT (stderr, "----------------- codec/base64 ---------------\n");
     411    CF_DEBUG_PRINT (stderr, "data   : %s\n", data);
     412    CF_DEBUG_PRINT (stderr, "= Convert binary to base64 =\n");
     413    CF_Codec_Base64_Encode ((unsigned char *)data, strlen (data), encode);
     414    CF_DEBUG_PRINT (stderr, "base64 : %s\n", encode);
     415
     416    CF_DEBUG_PRINT (stderr, "= Convert base64 to binary =\n");
     417    CF_Codec_Base64_Decode (encode, bin, &length);
     418    CF_DEBUG_PRINT_BIN (stderr, bin, length, "bin    : %s\n", bin);
     419}
Note: See TracChangeset for help on using the changeset viewer.