[링크]빠른 base64 인코딩/디코딩 소스
빠른 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 』
원래 코드에서
원래 코드에서 구조체를 다음과 같이 엔디언에 따라 다르게 잡으면 빅에서나 리틀에서나 똑같이 작동합니다.
typedef union{ struct{ #ifdef LITTLE_ENDIAN unsigned char c1,c2,c3; #else unsigned char c3,c2,c1; #endif }; struct{ #ifdef LITTLE_ENDIAN unsigned int e1:6,e2:6,e3:6,e4:6; #else unsigned int e4:6,e3:6,e2:6,e1:6; #endif }; } BF;소스코드는 ironiris 님의 코드에서 구조체만 위에서와 같이 엔디언에따라 나누고 코드에서는 리틀엔디언, 빅엔디언에따른 처리를 따로 하지 않았습니다. 그리고, 다른 컴파일러는 모르겠지만, x86의 gcc에서는 LITTLE_ENDIAN 이 선언되어있네요.
----
그리고, 제가 사용한 머신에서는 <endian.h> 헤더파일이 없네요. 오래된 컴터라서 그런가...
나도 세벌식을 씁니다