#include "cuEnc64.h"
#include <stdlib.h>
#ifndef NULL
#define NULL ((void *)0)
#endif
static const
unsigned char bintoasc[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const
unsigned char asctobin[] =
{
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x3e, 0x80, 0x80, 0x80, 0x3f,
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
0x3c, 0x3d, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
0x17, 0x18, 0x19, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
0x31, 0x32, 0x33, 0x80, 0x80, 0x80, 0x80, 0x80
};
#define ENC(c) (bintoasc[((c) & 0x3f)])
#define PAD '='
static void encChunk(const unsigned char *inp,
unsigned char *outp,
int count)
{
unsigned char c1, c2, c3, c4;
c1 = *inp >> 2;
c2 = ((inp[0] << 4) & 0x30) | ((inp[1] >> 4) & 0xf);
c3 = ((inp[1] << 2) & 0x3c) | ((inp[2] >> 6) & 0x3);
c4 = inp[2] & 0x3f;
*outp++ = ENC(c1);
*outp++ = ENC(c2);
if (count == 1) {
*outp++ = PAD;
*outp = PAD;
} else {
*outp++ = ENC(c3);
if (count == 2) {
*outp = PAD;
}
else {
*outp = ENC(c4);
}
}
}
unsigned char *enc64(const unsigned char *inbuf,
unsigned inlen,
unsigned *outlen) {
return enc64WithLines(inbuf, inlen, 0, outlen);
}
unsigned char *enc64WithLines(const unsigned char *inbuf,
unsigned inlen,
unsigned linelen,
unsigned *outlen)
{
unsigned outTextLen;
unsigned len; unsigned olen = 0; unsigned char *outbuf;
unsigned char endbuf[3];
int i;
unsigned char *outp;
unsigned numLines;
unsigned thisLine;
outTextLen = ((inlen + 2) / 3) * 4;
if(linelen) {
if((linelen & 0x03) != 0) {
linelen = (linelen + 3) & 0xfffffffc;
}
numLines = (outTextLen + linelen - 1)/ linelen;
}
else {
numLines = 1;
}
len = outTextLen + (2 * numLines) + 1;
outbuf = (unsigned char*)malloc(len);
outp = outbuf;
thisLine = 0;
while(inlen) {
if(inlen < 3) {
for(i=0; i<3; i++) {
if(i < inlen) {
endbuf[i] = inbuf[i];
}
else {
endbuf[i] = 0;
}
}
encChunk(endbuf, outp, inlen);
inlen = 0;
}
else {
encChunk(inbuf, outp, 3);
inlen -= 3;
inbuf += 3;
}
outp += 4;
thisLine += 4;
olen += 4;
if((linelen != 0) && (thisLine >= linelen) && inlen) {
*outp++ = '\n';
olen++;
thisLine = 0;
}
}
*outp++ = '\n';
*outp = '\0';
olen += 2;
*outlen = olen;
return outbuf;
}
static inline int isWhite(unsigned char c)
{
switch(c) {
case '\n':
case '\r':
case ' ':
case '\t':
case '\0':
return 1;
default:
return 0;
}
}
static unsigned char *stringCleanse(const unsigned char *inbuf,
unsigned inlen,
unsigned *outlen)
{
unsigned char *news; unsigned newsDex; unsigned i;
news = (unsigned char*)malloc(inlen);
newsDex = 0;
for(i=0; i<inlen; i++) {
if(!isWhite(inbuf[i])) {
news[newsDex++] = inbuf[i];
}
}
*outlen = newsDex;
return news;
}
unsigned char *dec64(const unsigned char *inbuf,
unsigned inlen,
unsigned *outlen)
{
unsigned char *outbuf;
unsigned char *outp; unsigned obuflen;
const unsigned char *bp;
unsigned olen = 0; unsigned char c1, c2, c3, c4;
unsigned char j;
unsigned thisOlen;
unsigned char *news; unsigned newsLen;
news = stringCleanse(inbuf, inlen, &newsLen);
if((newsLen & 0x03) != 0) {
free(news);
return (unsigned char*) NULL;
}
inlen = newsLen;
bp = news;
obuflen = (inlen / 4) * 3;
outbuf = (unsigned char*)malloc(obuflen);
outp = outbuf;
while (inlen) {
if (*bp & 0x80 || (c1 = asctobin[*bp]) & 0x80) {
goto errorOut;
}
inlen--;
bp++;
if (*bp & 0x80 || (c2 = asctobin[*bp]) & 0x80){
goto errorOut;
}
inlen--;
bp++;
if (*bp == PAD) {
c3 = c4 = 0;
thisOlen = 1;
if (c2 & 0xf) {
goto errorOut;
}
bp++;
inlen--;
if (*bp == PAD) {
bp++;
inlen--;
if(inlen > 0) {
goto errorOut;
}
}
else {
goto errorOut;
}
} else if (*bp & 0x80 || (c3 = asctobin[*bp]) & 0x80) {
goto errorOut;
} else {
bp++;
inlen--;
if (*bp == PAD) {
c4 = 0;
thisOlen = 2;
if (c3 & 3) {
goto errorOut;
}
} else if (*bp & 0x80 || (c4 = asctobin[*bp]) & 0x80) {
goto errorOut;
} else {
thisOlen = 3;
}
bp++;
inlen--;
}
j = (c1 << 2) | (c2 >> 4);
*outp++ = j;
if(thisOlen > 1) {
j = (c2 << 4) | (c3 >> 2);
*outp++ = j;
if(thisOlen == 3) {
j = (c3 << 6) | c4;
*outp++ = j;
}
}
olen += thisOlen;
}
free(news);
*outlen = olen;
return outbuf;
errorOut:
free(news);
free(outbuf);
return (unsigned char*) NULL;
}
int isValidEnc64(const unsigned char *inbuf,
unsigned inlen)
{
int padChars = 0; int validEncChars = 0;
unsigned char c;
while(inlen) {
c = *inbuf++;
inlen--;
if(isWhite(c)) {
continue;
}
if(c == PAD) {
if(++padChars > 2) {
return 0; }
}
else if(padChars > 0) {
return 0; }
else if((c & 0x80) || ((asctobin[c]) & 0x80)) {
return 0; }
validEncChars++;
}
if((validEncChars & 0x03) != 0) {
return 0;
}
else {
return 1;
}
}