#include<sys/types.h>
#include<stdio.h>
#include<stdlib.h>
#include<iconv.h>
#include<string.h>
#include<strings.h>

char base64chars[] = { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" };

int __debase64(unsigned char *_in, unsigned char *out){ /* Convert 4 Characters from IN to OUT */
	unsigned char in[4];
	int i;

	in[0] = _in[0];
	in[1] = _in[1];
	in[2] = _in[2];
	in[3] = _in[3];

	for ( i = 0; i < 4; i++ ){
		if ( _in[i] == '/' ){
			in[i] = 63;
			continue;
		}
		if ( _in[i] == '+' ){
			in[i] = 62;
			continue;
		}
		if ( _in[i] >= '0' && _in[i] <= '9' ){
			in[i] -= '0';
			in[i] += 26 + 26;
			continue;
		}
		if ( _in[i] >= 'a' && _in[i] <= 'z' ){
			in[i] -= 'a';
			in[i] += 26;
			continue;
		}
		if ( _in[i] >= 'A' && _in[i] <= 'Z' ){
			in[i] -= 'A';
			continue;
		}
		if ( _in[i] == '=' ){
			in[i] = 255; /* Padding character */
			continue;
		}
		return(-1); /* Broken INPUT Stream!!! */
	}
	if ( in[0] == 255 || in[1] == 255 )
		return(0);
	out[0] = (in[0] << 2) + (in[1] >> 4);
	if ( in[2] ==255)
		return(1);
	out[1] = ((in[1]&0x0F)<<4) + (in[2]>>2);
	if ( in[3] == 255 )
		return(2);

	out[2] = in[3] + ((in[2] & 0x03)<<6);

	return(3);

}

int debase64(unsigned char *in, unsigned char *out){
	int j; 
	unsigned char translated[16];	
	unsigned char *copy;
	int count;
	int total;	
	copy = (unsigned char *)malloc(strlen(in) + 10);
	strcpy(copy,in);
	/* Add Padding if missing... */
	for ( j = strlen(in); j < ((4-(strlen(in)%4)) + strlen(in)); j++ )
		copy[j] = '=';
	copy[j] = '\0';


	total = 0;	
	for ( j = 0; j < strlen(copy); j+= 4 ){
		count  =  __debase64(&copy[j],translated);
		if ( count == -1 ){
			free(copy);
			return(-1);
		}
		if ( count > 0 )
			bcopy(translated,&out[total],count);
		total += count;
	}	
	out[total] = '\0';
	free(copy);
	return(total);
}

char *_base64(unsigned char *in, int len){
	static char ret[5];
	strcpy(ret,"====");
	if ( len == 0 )
		return(ret);	
	ret[0] = base64chars[in[0]>>2];
	ret[1] = base64chars[(in[0]&0x03)<<4];
	if ( len == 1 )
		return(ret);
	ret[1] = base64chars[((in[0]&0x03)<<4)+(in[1]>>4)];
	ret[2] = base64chars[(in[1]&0x0F)<<2];
	if ( len == 2 )
		return(ret);
	ret[2] = base64chars[((in[1]&0x0F)<<2) + (in[2]>>6)];
	ret[3] = base64chars[in[2] & 0x3F];	
	return(ret);	
}

int base64(unsigned char *in, int len, char *out){ /* Use an INPUT Len of 57 for standard encoding */
	int i;
	int length;
	strcpy(out,"");

	i = 0;
	while(1){
		if ( i > len )
			break;
		if ( ( i + 3 ) > len )
			length = len - i;
		else 
			length = 3;
		if ( length ){
			strcat(out,_base64(&in[i],length));
		}
		i += 3;
	}
	return(strlen(out));
}


struct bas32 {
        unsigned char bitval;
        unsigned char repval;
};

struct bas32 base32[] = {
        { 0, 0x61 },
        { 1, 0x62 },
        { 2, 0x63 },
        { 3, 0x64 },
        { 4, 0x65 },
        { 5, 0x66 },
        { 6, 0x67 },
        { 7, 0x68 },
        { 8, 0x69 },
        { 9, 0x6a },
        { 10, 0x6b },
        { 11, 0x6c },
        { 12, 0x6d },
        { 13, 0x6e },
        { 14, 0x6f },
        { 15, 0x70 },
        { 16, 0x71 },
        { 17, 0x72 },
        { 18, 0x73 },
        { 19, 0x74 },
        { 20, 0x75 },
        { 21, 0x76 },
        { 22, 0x77 },
        { 23, 0x78 },
        { 24, 0x79 },
        { 25, 0x7a },
        { 26, 0x32 },
        { 27, 0x33 },
        { 28, 0x34 },
        { 29, 0x35 },
        { 30, 0x36 },
        { 31, 0x37 }
};




int race_it(unsigned char *input, int inlen, unsigned char *output, int *outlen){
        int i,j;
        int gleich;
        unsigned char *u1, *n1, *u2;
        unsigned char *start;
        unsigned char old_u1;
        int outptr;

        sprintf(output,"");

        outptr = 0;



        gleich = 1;

        u1 = &input[0];
        old_u1 = *u1;

        for ( i = 2; i < inlen; i += 2 ){
                if ( input[i] != *u1 && input[i] != old_u1){
                        gleich--;
                        old_u1 = input[i];
                }
        }



        if ( gleich == 1 || gleich == 0 ){
                if ( *u1 == 0xd8 || *u1 == 0xdc )
                        return(-1);
                output[outptr++] = *u1;
        }

        if ( gleich < 0 ){
                output[0] = 0xd8;
                for ( i = 0; i < inlen; i++ )
                        output[i+1] = input[i];
                *outlen  = inlen+1;
                return(0);
        }




        start = &input[0];
        while(1){
                if ( start - input >= inlen ){
                        *outlen = outptr;
                        return(0);
                }
                u2 = start;
                n1 = start+1;
                if ( *n1 == 0x99 && *u2 == 0x00 ){
                        return(-1);
                }
                if ( *u2 == *u1 && *n1 != 0xFF ){
                        output[outptr++] = *n1;
                        start++;
                        start++;
                        continue;
                }
                if ( *u2 == *u1 && *n1 == 0xFF ){
                        output[outptr++] = 0xFF;
                        output[outptr++] = 0x99;
                        start++;
                        start++;
                        continue;
                }
                start++;
                start++;
                output[outptr++] = 0xFF;
                output[outptr++] = *n1;
        }








        return(0);

}


unsigned char ap__ap__ap__bitfeld[1024];



void addbitval(unsigned char bitval,int offset, unsigned char *output){
        int bitoffset;
        int byteoffset;

        bitoffset = offset * 5;


        if ( bitval & 16 )
                ap__ap__ap__bitfeld[bitoffset] = '1';
        else
                ap__ap__ap__bitfeld[bitoffset] = '0';

        if ( bitval & 8 )
                ap__ap__ap__bitfeld[bitoffset+1] = '1';
        else
                ap__ap__ap__bitfeld[bitoffset+1] = '0';

        if ( bitval & 4 )
                ap__ap__ap__bitfeld[bitoffset+2] = '1';
        else
                ap__ap__ap__bitfeld[bitoffset+2] = '0';

        if ( bitval & 2 )
                ap__ap__ap__bitfeld[bitoffset+3] = '1';
        else
                ap__ap__ap__bitfeld[bitoffset+3] = '0';

        if ( bitval & 1 )
                ap__ap__ap__bitfeld[bitoffset+4] = '1';
        else
                ap__ap__ap__bitfeld[bitoffset+4] = '0';



        return;



}



int de_base32_it(unsigned char *input, unsigned char *output, int *outlen){
        int i;
        int j;
        bzero(output,*outlen);
        bzero(ap__ap__ap__bitfeld,1024);
        for ( i = 0; i < strlen(input); i++ ){
                for ( j = 0; j < 32; j++ ){
                        if ( base32[j].repval == input[i] ){
                                addbitval(base32[j].bitval, i,output);
                                break;
                        }
                }
                if ( j == 32 ){
                        return(-1);
                }
        }
        /* printf("Bitfeld: '%s'[%d]\n",ap__ap__ap__bitfeld,strlen(ap__ap__ap__bitfeld)); */
        for ( j = 0; j < strlen(ap__ap__ap__bitfeld); j +=  8 ){
                output[j/8] = 0;
                for ( i = 0; i < 8; i++ ){
                        if ( ap__ap__ap__bitfeld[j+i] == '1' ){
                                output[j/8] += (1 << (7 - i));
                        }

                }
        }
        output[j/8] = '\0';
        *outlen = j/8 - 1;
        return(0);



}


int base32_it(unsigned char *input, int len, unsigned char *out, int *outlen){

        /* Convert it to a bitfield... */
        int bitfieldptr;
        int i,j;

        bitfieldptr = 0;
        bzero(ap__ap__ap__bitfeld,1024);

        for ( i = 0; i < len; i++ ){
                for ( j = 7; j >= 0 ; j-- ){
                        if ( input[i] & ( 1 << j ) ){
                                ap__ap__ap__bitfeld[bitfieldptr++] = '1';
                        } else {
                                ap__ap__ap__bitfeld[bitfieldptr++] = '0';
                        }
                }
        }
        /* Add padding */
        while ( bitfieldptr % 5 ){
                ap__ap__ap__bitfeld[bitfieldptr++] = '0';
        }
        *outlen = bitfieldptr / 5;
        bzero(out,*outlen + 1 );
        /* printf("Bitfeld: '%s'[%d]\n",ap__ap__ap__bitfeld,strlen(ap__ap__ap__bitfeld)); */
        for ( i = 0; i < *outlen * 5; i += 5 ){
                int indx;
                for ( j = 0; j < 5; j++ ){
                        if ( ap__ap__ap__bitfeld[i+j] == '1' ){
                                out[i/5] |= ( 1 << (4 - j) );
                        }
                }
                /* printf("OUT[%d] = %02X\n",i/5,out[i/5]); */
                indx = (int) out[i/5];
                out[i/5] = base32[indx].repval;
        }
        out[(i/5)+1] = '\0';

        return(0);

}


