빠른 base64 인코딩/디코딩 소스
필요한 부분만 가져왔습니다.
앞부분 생략
--------------------------------------------------------------
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <endian.h> static const char MimeBase64[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' }; static int DecodeMimeBase64[256] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 00-0F */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 10-1F */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, /* 20-2F */ 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1, /* 30-3F */ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, /* 40-4F */ 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, /* 50-5F */ -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, /* 60-6F */ 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, /* 70-7F */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 80-8F */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 90-9F */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* A0-AF */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* B0-BF */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* C0-CF */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* D0-DF */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* E0-EF */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 /* F0-FF */ }; typedef union{ struct{ unsigned char c1,c2,c3; }; struct{ unsigned int e1:6,e2:6,e3:6,e4:6; }; } BF; int endian = 0; // little : 0, big : 1 void base64e(char *src, char *result, int length){ int i, j = 0; BF temp; if(endian == 0){ // little endian(intel) for(i = 0 ; i < length ; i = i+3, j = j+4){ temp.c3 = src[i]; if((i+1) > length) temp.c2 = 0x00; else temp.c2 = src[i+1]; if((i+2) > length) temp.c1 = 0x00; else temp.c1 = src[i+2]; result[j] = MimeBase64[temp.e4]; result[j+1] = MimeBase64[temp.e3]; result[j+2] = MimeBase64[temp.e2]; result[j+3] = MimeBase64[temp.e1]; if((i+2) > length) result[j+2] = '='; if((i+3) > length) result[j+3] = '='; } } else { // big endian(sun) for(i = 0 ; i < length ; i = i+3, j = j+4){ temp.c1 = src[i]; if((i+1) > length) temp.c2 = 0x00; else temp.c2 = src[i+1]; if((i+2) > length) temp.c3 = 0x00; else temp.c3 = src[i+2]; result[j] = MimeBase64[temp.e4]; result[j+1] = MimeBase64[temp.e3]; result[j+2] = MimeBase64[temp.e2]; result[j+3] = MimeBase64[temp.e1]; if((i+2) > length) result[j+2] = '='; if((i+3) > length) result[j+3] = '='; } } } void base64d(char *src, char *result, int *length){ int i, j = 0, src_length, blank = 0; BF temp; src_length = strlen(src); if(endian == 0){ // little endian(intel) for(i = 0 ; i < src_length ; i = i+4, j = j+3){ temp.e4 = DecodeMimeBase64[src[i]]; temp.e3 = DecodeMimeBase64[src[i+1]]; if(src[i+2] == '='){ temp.e2 = 0x00; blank++; } else temp.e2 = DecodeMimeBase64[src[i+2]]; if(src[i+3] == '='){ temp.e1 = 0x00; blank++; } else temp.e1 = DecodeMimeBase64[src[i+3]]; result[j] = temp.c3; result[j+1] = temp.c2; result[j+2] = temp.c1; } } else { // big endian(sun) for(i = 0 ; i < src_length ; i = i+4, j = j+3){ temp.e4 = DecodeMimeBase64[src[i]]; temp.e3 = DecodeMimeBase64[src[i+1]]; if(src[i+2] == '='){ temp.e2 = 0x00; blank++; } else temp.e2 = DecodeMimeBase64[src[i+2]]; if(src[i+3] == '='){ temp.e1 = 0x00; blank++; } else temp.e1 = DecodeMimeBase64[src[i+3]]; result[j] = temp.c1; result[j+1] = temp.c2; result[j+2] = temp.c3; } } *length = j-blank; } int main(void){ char str1[]="테스트문자열입니다.ABCabc123,./"; char str2[]="7YWM7Iqk7Yq466y47J6Q7Je07J6F64uI64ukLkFCQ2FiYzEyMywuLw=="; char *result; int src_size; struct timespec start,end; if (__LITTLE_ENDIAN == BYTE_ORDER) endian == 0; else endian == 1; src_size = strlen(str1); result = (char *)malloc((4 * (src_size / 3)) + (src_size % 3 ? 4 : 0) + 1); clock_gettime(CLOCK_REALTIME, &start); base64e(str1, result, src_size); clock_gettime(CLOCK_REALTIME, &end); float time_dif = (end.tv_sec - start.tv_sec) + ((end.tv_nsec - start.tv_nsec) ); printf("함수 수행 시간: %f\n", time_dif); printf("%s\n%s\n",str1,result); free(result); src_size = strlen(str2); result = (char *)malloc(3 * (src_size / 4)); base64d(str2,result,&src_size); printf("%s\n%s\n길이:%d\n",str2,result,src_size); free(result); }
===============================================================================
gcc 일 경우 little endian 과 big endian 을 구분해서 작동하도록 되어있습니다.
big endian 환경에서 컴파일할수 있으신 분들 테스트 부탁드려요.
네.. LITTLE_ENDIAN 으로
네.. LITTLE_ENDIAN 으로 선언되어있는 것을 사용하는 것이 더 좋겠네요.
if 구문도 줄일수 있고요..
그럭저럭 사용할 수 있는 코드가 된 듯 하니 다행이네요. :)
음...
__LITTLE_ENDIAN, __BIG_ENDIAN, __BYTE_ORDER 는 endian.h 에 define 되어 있어서..
#ifdef 로 사용하면 낭패를 볼 수 있습니다.
(__USE_BSD 가 define 되면, LITTLE_ENDIAN, BIG_ENDIAN, BYTE_ORDER 가 추가됩니다)
#if __BYTE_ORDER == __LITTLE_ENDIAN 와 같이 사용하시는게 좋을 것 같습니다.
되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』
되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』
아닙니다. LITTLE_ENDIAN
아닙니다. LITTLE_ENDIAN 은 gcc 컴파일러에서 미리 선언해주는 것 같습니다.
위에서 사용한 헤더는 stdio, stdlib, string 뿐입니다.
----
stdlib 헤더를 빼니깐 LITTLE_ENDIAN 선언이 없어지네요. 아마 저 안쪽 어디에서 endian 헤더를 추가하는 듯 합니다.
나도 세벌식을 씁니다
음..
gcc predefined macros 에는 ENDIAN 에 대한 언급은 없는 걸로 알고 있습니다.
해당 시스템의 endian 정의는 system header 에 의존적이구요..
혹시나 해서 다시 헤더를 살펴봤습니다.
features.h 를 보니, 별다른 옵션이 없는 경우에는 _BSD_SOURCE (__USE_BSD) 가 켜지는 듯 하네요.
이 경우에는 stdlib.h 가 sys/types.h -> endian.h 을 include 하구요.
이 때 LITTLE_ENDIAN 이 1234 로 define 됩니다. (BIG_ENDIAN 은 4321)
$ fih LITTLE_ENDIAN | grep '\# *define'
/usr/include/bits/endian.h:7:#define __BYTE_ORDER __LITTLE_ENDIAN
/usr/include/endian.h:32:#define __LITTLE_ENDIAN 1234
/usr/include/endian.h:46:# define LITTLE_ENDIAN __LITTLE_ENDIAN
되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』
되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』
원래 코드에서
원래 코드에서 구조체를 다음과 같이 엔디언에 따라 다르게 잡으면 빅에서나 리틀에서나 똑같이 작동합니다.
소스코드는 ironiris 님의 코드에서 구조체만 위에서와 같이 엔디언에따라 나누고 코드에서는 리틀엔디언, 빅엔디언에따른 처리를 따로 하지 않았습니다. 그리고, 다른 컴파일러는 모르겠지만, x86의 gcc에서는 LITTLE_ENDIAN 이 선언되어있네요.
----
그리고, 제가 사용한 머신에서는 <endian.h> 헤더파일이 없네요. 오래된 컴터라서 그런가...
나도 세벌식을 씁니다