C :: Aufgabe #105

2 Lösungen Lösungen öffentlich

Base64 - Kodierung/-Dekodierung

Fortgeschrittener - C von devnull - 14.03.2016 um 14:42 Uhr
Base64 ist ein Verfahren zur Kodierung von 8-Bit-Binärdaten und wird häufig zum Kodieren von Email-Anhängen verwendet.
Schreibe wahlweise einen Base64-Encoder oder einen Base64-Decoder. Wer Lust hat, kann natürlich auch beide Funktionen in einem Programm kombinieren.

Lösungen:

1 Kommentar
vote_ok
von devnull (8870 Punkte) - 14.03.2016 um 18:16 Uhr

Konsolenausgabe:

$ echo "Polyfon zwitschernd aßen Mäxchens Vögel Rüben, Joghurt und Quark" |\
./base64 -encode | tee base64.txt | ./base64 -decode
Polyfon zwitschernd aßen Mäxchens Vögel Rüben, Joghurt und Quark
$ cat base64.txt
UG9seWZvbiB6d2l0c2NoZXJuZCBhw59lbiBNw6R4Y2hlbnMgVsO2Z2VsIFLDvGJlbiwgSm9naHVy
dCB1bmQgUXVhcmsK

Quellcode ausblenden C-Code
/*****************************
 * base64.c
 *****************************/
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>

#define LF "\n"

char base64_enctab[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 				       "abcdefghijklmnopqrstuvwxyz"
					   "0123456789+/=";

int8_t base64_dectab[] = {
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 127, -1, -1, 127, -1, -1, 
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 
	54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 64, -1, -1, -1, 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, -1, -1, -1, -1, -1, -1, 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, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};

void base64_encode(FILE *in, FILE *out) {
    uint8_t b1, b2, b3, b4;
    uint8_t c1, c2, c3;
    int bcnt=0, c, pad;

	do {
        pad = 3;
        if ((c = fgetc(in)) != EOF) {
			c1 = (uint8_t)c;
            pad--;
            if ((c = fgetc(in)) != EOF) {
				c2 = (uint8_t)c;
                pad--;
                if ((c = fgetc(in)) != EOF) {
					c3 = (uint8_t)c;
                    pad--;
                }
            }
        }
        else 
            break;
            
        b1 = (c1 & 0xFC)>>2;
        b2 = ((c1 & 0x03)<<4)|((c2 & 0xF0)>>4);
        b3 = (pad<2)?(((c2 & 0x0F)<<2)|((c3 & 0xC0)>>6)):64;
        b4 = (pad<1)?(c3 & 0x3F):64;
        bcnt += 4;    
        fprintf(out, "%c%c%c%c", base64_enctab[b1],
                                 base64_enctab[b2],
                                 base64_enctab[b3],
                                 base64_enctab[b4]);
		/* encoded line with 76 characters */
        if (bcnt%76==0)
            fprintf(out, LF);
        
    } while (c != EOF);
}

int base64_decode(FILE *in, FILE *out) {
    uint8_t c1, c2, c3;
    uint8_t c, ac[4];
    int b=0, cntb=0, pad=0, nc;

	do {
        nc = 0;
        while (nc < 4) {
			if ((b = fgetc(in)) != EOF) {
				cntb++;
				if ((c = base64_dectab[b]) < 0)
					/* illegal character */
					return -1;
				else if (c == 127) {
					/* skip line feed */
					continue;
				}
				else if (b == '=') {
					/* padding byte */
					pad++;
					if (pad > 2)
						break;
					nc++;
				}
				else {
					if (pad)
						return -1;
					else
						ac[nc++] = c;
				}
			}
			else 
				break;
        }
		if (nc == 4) {
			c1 = (ac[0]<<2)|((ac[1] & 0x30)>>4);
			c2 = ((ac[1] & 0x0F)<<4)|((ac[2] & 0x3C)>>2);
			c3 = ((ac[2] & 0x03)<<6)|(ac[3]);
			fprintf(out, "%c%c%c", c1, c2, c3);
		}
    } while (b != EOF);
	if (nc > 0)
		return -1;
    return 0;
}

int main(int argc, char **argv) {
	if (argc > 1) {
		if ((strcmp(argv[1], "-encode") == 0)) {
			base64_encode(stdin, stdout);
		} else 
		if ((strcmp(argv[1], "-decode")==0)) {
			if (base64_decode(stdin, stdout) < 0)
			  fprintf(stderr, "Keine gültige Base64-Kodierung.\n");
		} else {	
			printf("Usage:  base64 -encode\n");
			printf("        base64 -decode\n");
			printf(" Eingabe=stdin, Ausgabe=stdout\n");
		}
	}
	return 0;
}
vote_ok
von devnull (8870 Punkte) - 17.03.2016 um 21:26 Uhr
Eine Lösung, die Bit-Manipulationen mit dem Datentyp uint32_t durchführt. Hat vielleicht einen geringen Vorteil, falls die CPU-Architektur einen performanten Bitshifter zur Verfügung stellt.
Quellcode ausblenden C-Code
/*****************************
 * base64_2.c  (uint32_t)
 *****************************/
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>

#define LF "\n"

char base64_enctab[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 				       "abcdefghijklmnopqrstuvwxyz"
					   "0123456789+/=";

int8_t base64_dectab[] = {
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 127, -1, -1, 127, -1, -1, 
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 
	54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 64, -1, -1, -1, 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, -1, -1, -1, -1, -1, -1, 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, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};

void base64_encode(FILE *in, FILE *out) {
    uint32_t bc1, bc2, bc3, bc4;
    uint32_t c, ccc;
    int bcnt=0, pad;

	do {
        ccc = 0;
        pad = 3;
        if ((c = fgetc(in)) != EOF) {
            ccc |= (c<<16);
            pad--;
            if ((c = fgetc(in)) != EOF) {
                ccc |= (c<<8);
                pad--;
                if ((c = fgetc(in)) != EOF) {
                    ccc |= c;
                    pad--;
                }
            }
        }
        else 
            break;
	
        bc1 = (ccc & 0xFC0000)>>18;
        bc2 = (ccc & 0x03F000)>>12;
        bc3 = (pad<2)?((ccc & 0x000FC0)>>6):64;
        bc4 = (pad<1)?(ccc & 0x00003F):64;
        bcnt += 4;    
        fprintf(out, "%c%c%c%c", base64_enctab[bc1],
                                 base64_enctab[bc2],
                                 base64_enctab[bc3],
                                 base64_enctab[bc4]);
		/* encoded line with 76 characters */
        if (bcnt%76==0)
            fprintf(out, LF);
            
    } while (c != EOF);
}

int base64_decode(FILE *in, FILE *out) {
    uint32_t c, c1, c2, c3;
    uint32_t b, bbbb;
    int pad=0, nc;

	do {
        bbbb = 0;
        nc = 0;
        while (nc < 4) {
			if ((b = fgetc(in)) != EOF) {
				if ((c = base64_dectab[b]) < 0) {
					/* illegal character */
					return -1;
				}
				else if (c == 127) {
					/* line feed character */
					continue;
				}
				else if (c == 64) {
					/* padding byte */
					pad++;
					if (pad > 2)
						break;
					nc++;
				}
				else {
					if (pad)
						return -1;
					else {
						nc++;
						bbbb |= c << (24-nc*6);
					}
				}
			}
			else 
				break;
        }
        if (nc==4) {
			c1 = (bbbb & 0xFF0000)>>16;
			c2 = (bbbb & 0x00FF00)>>8;
			c3 = (bbbb & 0x0000FF);
			fprintf(out, "%c%c%c", c1, c2, c3);
		}
    } while (b != EOF);
	if (nc > 0)
		return -1;
    return 0;
}

int main(int argc, char **argv) {
	if (argc > 1) {
		if ((strcmp(argv[1], "-encode") == 0)) {
			base64_encode(stdin, stdout);
		} else 
		if ((strcmp(argv[1], "-decode")==0)) {
			if (base64_decode(stdin, stdout) < 0)
			  fprintf(stderr, "Keine gültige Base64-Kodierung.\n");
		} else {	
			printf("Usage:  base64 -encode\n");
			printf("        base64 -decode\n");
			printf(" Eingabe=stdin, Ausgabe=stdout\n");
		}
	}
	return 0;
}