Created
March 8, 2011 06:44
-
-
Save ACUVE/859952 to your computer and use it in GitHub Desktop.
base64プログラム
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstdio> | |
#include <cstring> | |
#include <cstdlib> | |
#include <fstream> | |
//#include <iostream> | |
#include <string> | |
#include <exception> | |
#include <stdexcept> | |
#include "scope_exit.hpp" | |
bool base64decode(char const * const base64, unsigned int const plen, void ** const ret, unsigned int * const psize){ | |
static char const list[] = { | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63, | |
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, | |
0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, | |
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, | |
0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, | |
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
}; | |
unsigned int const len = plen ? plen : std::strlen(base64); | |
if(len & 0x3){ | |
return false; | |
} | |
bool const haspadding = base64[len - 1] == '=', hastwopadding = base64[len - 2] == '='; | |
unsigned int const fulllen = (len >> 2) - haspadding; | |
unsigned char *retdata = new(std::nothrow) unsigned char[*psize = fulllen * 3 + (haspadding ? hastwopadding ? 1 : 2 : 0)]; | |
*ret = retdata; | |
unsigned char const *basedata = reinterpret_cast<unsigned char const*>(base64); | |
for(unsigned int i = fulllen; ~(--i); basedata += 4, retdata += 3){ | |
unsigned char const ddata[] = {list[basedata[0]], list[basedata[1]], list[basedata[2]], list[basedata[3]]}; | |
retdata[0] = (ddata[0] << 2) | (ddata[1] >> 4); | |
retdata[1] = (ddata[1] << 4) | (ddata[2] >> 2); | |
retdata[2] = (ddata[2] << 6) | ddata[3]; | |
} | |
if(haspadding){ | |
if(hastwopadding){ | |
retdata[0] = (list[basedata[0]] << 2) | (list[basedata[1]] >> 4); | |
}else{ | |
unsigned char const ddata[] = {list[basedata[0]], list[basedata[1]], list[basedata[2]]}; | |
retdata[0] = (ddata[0] << 2) | (ddata[1] >> 4); | |
retdata[1] = (ddata[1] << 4) | (ddata[2] >> 2); | |
} | |
} | |
return true; | |
} | |
bool base64encode(void const * const data, unsigned int const size, char ** const ret){ | |
static char const * const list = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | |
unsigned int const fullsize = size / 3, rest = size % 3; | |
unsigned char *retp = new(std::nothrow) unsigned char[(fullsize + (rest ? 1 : 0)) * 4 + 1]; | |
*ret = reinterpret_cast<char*>(retp); | |
unsigned char const *datap = static_cast<unsigned char const*>(data); | |
if(retp == NULL){ | |
return false; | |
} | |
for(unsigned int i = fullsize; ~(--i); datap += 3, retp += 4){ | |
retp[0] = list[datap[0] >> 2]; | |
retp[1] = list[(datap[0] & 0x3) << 4 | datap[1] >> 4]; | |
retp[2] = list[(datap[1] & 0xF) << 2 | datap[2] >> 6]; | |
retp[3] = list[datap[2] & 0x3F]; | |
} | |
switch(rest){ | |
case 1:{ | |
retp[0] = list[datap[0] >> 2]; | |
retp[1] = list[(datap[0] & 0x3) << 4]; | |
retp[2] = retp[3] = '='; | |
retp += 4; | |
break; | |
} | |
case 2:{ | |
retp[0] = list[datap[0] >> 2]; | |
retp[1] = list[(datap[0] & 0x3) << 4 | datap[1] >> 4]; | |
retp[2] = list[(datap[1] & 0xF) << 2]; | |
retp[3] = '='; | |
retp += 4; | |
break; | |
} | |
} | |
retp[0] = '\0'; | |
return true; | |
} | |
void base64free(void *base64){ | |
delete[] static_cast<unsigned char*>(base64); | |
} | |
int main(int argc, char **argv){ | |
try{ | |
if(argc < 2) throw std::runtime_error("引数が足りません"); | |
if(argc == 2){ | |
FILE *file = std::fopen(argv[1], "rb"); | |
if(!file) throw std::runtime_error("fopenエラー"); | |
scope_exit{std::fclose(file);}; | |
if(std::fseek(file, 0, SEEK_END)) throw std::runtime_error("fseekエラー1"); | |
long size = std::ftell(file); | |
if(size == -1) throw std::runtime_error("ftellエラー"); | |
if(std::fseek(file, 0, SEEK_SET)) throw std::runtime_error("fseekエラー2"); | |
char *data = static_cast<char*>(std::malloc(size * sizeof(char))); | |
if(!data) throw std::runtime_error("mallocエラー"); | |
scope_exit{std::free(data);}; | |
if(!std::fread(data, size, 1, file)) throw std::runtime_error("freadエラー"); | |
char *ret; | |
if(!base64encode(data, size, &ret)) throw std::runtime_error("base64encodeエラー"); | |
scope_exit{base64free(ret);}; | |
std::puts(ret); | |
}else if(argc == 3){ | |
std::ifstream file(argv[1]); | |
if(!file) throw std::runtime_error("ifstreamエラー"); | |
FILE *ofile = std::fopen(argv[2], "wb"); | |
if(!ofile) throw std::runtime_error("fopenエラー"); | |
std::string str; | |
std::getline(file, str); | |
if(!file) throw std::runtime_error("getlineエラー"); | |
void *p; | |
unsigned int size; | |
if(!base64decode(str.c_str(), str.length(), &p, &size)) throw std::runtime_error("base64decodeエラー"); | |
scope_exit{base64free(p);}; | |
if(!std::fwrite(p, size, 1, ofile)) throw std::runtime_error("fwriteエラー"); | |
}else{ | |
throw std::runtime_error("引数が多すぎます"); | |
} | |
}catch(std::exception &e){ | |
std::fprintf(stderr, "Exception is thrown. what:%s\n", e.what()); | |
return -1; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment