shithub: libtags

ref: f68e997ecefd77b3d1cd33c21264d5ced6e5d021
dir: /base64.c/

View raw version
#include "tagspriv.h"

static const uint8_t d[] = {
	66,66,66,66,66,66,66,66,66,66,64,66,66,66,66,66,66,66,66,66,66,66,66,66,66,
	66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,62,66,66,66,63,52,53,
	54,55,56,57,58,59,60,61,66,66,66,65,66,66,66, 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,66,66,66,66,66,66,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,66,66,
	66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,
	66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,
	66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,
	66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,
	66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,
	66,66,66,66,66,66
};
enum {
	B64_WHITESPACE = 64,
	B64_EQUALS,
	B64_INVALID,
};

int
debase64(uint8_t *in, int insz, uint8_t *out, int outsz)
{
	uint8_t *end = in + insz;
	uint8_t iter = 0;
	uint32_t buf = 0;
	int len = 0;

	while(in < end){
		uint8_t c = d[*in++];

		switch(c){
		case B64_WHITESPACE:
			continue;
		case B64_INVALID:
			return -1;
		case B64_EQUALS:
			in = end;
			continue;
		default:
			buf = buf << 6 | c;
			if(++iter == 4){
				if((len += 3) > outsz)
					return -1;
				*out++ = (buf >> 16) & 0xff;
				*out++ = (buf >> 8) & 0xff;
				*out++ = buf & 0xff;
				buf = 0;
				iter = 0;
			}
		}
	}

	if(iter == 3){
		if((len += 2) > outsz)
			return -1;
		*out++ = (buf >> 10) & 0xff;
		*out++ = (buf >> 2) & 0xff;
	}else if(iter == 2){
		if(++len > outsz)
			return -1;
		*out++ = (buf >> 4) & 0xff;
	}

	return len;
}