Suche schöne C++ Base64 Klasse



  • Hey!

    Natürlich habe ich google schon bemüht, aber ich finde einfach keine schöne, sauber programmierte C++ Lösung einer Base64 Klasse.
    Ich finde nur Codeschnipsel die nicht funktioneren oder welche die die MFC verwenden.
    Da ich selbst keine Zeit und auch keine Lust habe (Programmierer sind faul ;)) mich in die Theorie einzuarbeiten und das selber zu machen wollte ich einfach mal nachfragen.

    Die Klasse bräuchte nur die üblichen Decode / Encode Methoden. Es muss ja nichtmal eine Klasse sein, Hauptsache die Lösung ist brauchbar und standard C++ konform 🙂

    Danke!



  • Hallo,
    im Doom 3 SDK findest du solch eine Klasse basierend auf dem Code von Lars Wirzenius. Damit du dir das nicht alles runterladen musst, kopier ich einfach den Code 🙂
    Du musst den Code leicht modifizieren, damit du nicht von idStr, idFile, byte und ID_INLINE abhaengig bist, was aber kein Problem sein sollte.

    #ifndef __BASE64_H__
    #define __BASE64_H__
    
    /*
    ===============================================================================
    
    	base64
    
    ===============================================================================
    */
    
    class idBase64 {
    public:
    				idBase64( void );
    				idBase64( const idStr &s );
    				~idBase64( void );
    
    	void		Encode( const byte *from, int size );
    	void		Encode( const idStr &src );
    	int			DecodeLength( void ) const; // minimum size in bytes of destination buffer for decoding
    	int			Decode( byte *to ) const; // does not append a \0 - needs a DecodeLength() bytes buffer
    	void		Decode( idStr &dest ) const; // decodes the binary content to an idStr (a bit dodgy, \0 and other non-ascii are possible in the decoded content)
    	void		Decode( idFile *dest ) const;
    
    	const char	*c_str() const;
    
    	void 		operator=( const idStr &s );
    
    private:
    	byte *		data;
    	int			len;
    	int			alloced;
    
    	void		Init( void );
    	void		Release( void );
    	void		EnsureAlloced( int size );
    };
    
    ID_INLINE idBase64::idBase64( void ) {
    	Init();
    }
    
    ID_INLINE idBase64::idBase64( const idStr &s ) {
    	Init();
    	*this = s;
    }
    
    ID_INLINE idBase64::~idBase64( void ) {
    	Release();
    }
    
    ID_INLINE const char *idBase64::c_str( void ) const {
    	return (const char *)data;
    }
    
    ID_INLINE void idBase64::Init( void ) {
    	len = 0;
    	alloced = 0;
    	data = NULL;
    }
    
    ID_INLINE void idBase64::Release( void ) {
    	if ( data ) {
    		delete[] data;
    	}
    	Init();
    }
    
    ID_INLINE void idBase64::EnsureAlloced( int size ) {
    	if ( size > alloced ) {
    		Release();
    	}
    	data = new byte[size];
    	alloced = size;
    }
    
    ID_INLINE void idBase64::operator=( const idStr &s ) {
    	EnsureAlloced( s.Length()+1 ); // trailing \0 - beware, this does a Release
    	strcpy( (char *)data, s.c_str() );
    	len = s.Length();
    }
    
    #endif /* !__BASE64_H__ */
    
    /*
    Copyright (c) 1996 Lars Wirzenius.  All rights reserved.
    
    June 14 2003: TTimo <ttimo@idsoftware.com>
    	modified + endian bug fixes
    	http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=197039
    
    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions
    are met:
    
    1. Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
    
    2. Redistributions in binary form must reproduce the above copyright
       notice, this list of conditions and the following disclaimer in the
       documentation and/or other materials provided with the distribution.
    
    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.
    */
    
    /*
    ============
    idBase64::Encode
    ============
    */
    static const char sixtet_to_base64[] = 
    	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    
    void idBase64::Encode( const byte *from, int size ) {
    	int i, j;
    	unsigned long w;
    	byte *to;
    
    	EnsureAlloced( 4*(size+3)/3 + 2 ); // ratio and padding + trailing \0
    	to = data;
    
    	w = 0;
    	i = 0;
    	while (size > 0) {
    		w |= *from << i*8;
    		++from;
    		--size;
    		++i;
    		if (size == 0 || i == 3) {
    			byte out[4];
    			SixtetsForInt( out, w );
    			for (j = 0; j*6 < i*8; ++j) {
    				*to++ = sixtet_to_base64[ out[j] ];
    			}
    			if (size == 0) {
    				for (j = i; j < 3; ++j) {
    					*to++ = '=';
    				}
    			}
    			w = 0;
    			i = 0;
    		}
    	}
    
    	*to++ = '\0';
    	len = to - data;
    }
    
    /*
    ============
    idBase64::DecodeLength
    returns the minimum size in bytes of the target buffer for decoding
    4 base64 digits <-> 3 bytes
    ============
    */
    int idBase64::DecodeLength( void ) const {
    	return 3*len/4;
    }
    
    /*
    ============
    idBase64::Decode
    ============
    */
    int idBase64::Decode( byte *to ) const {
    	unsigned long w;
    	int i, j;
    	size_t n;
    	static char base64_to_sixtet[256];
    	static int tab_init = 0;
    	byte *from = data;
    
    	if (!tab_init) {
    		memset( base64_to_sixtet, 0, 256 );
    		for (i = 0; (j = sixtet_to_base64[i]) != '\0'; ++i) {
    			base64_to_sixtet[j] = i;
    		}
    		tab_init = 1;
    	}
    
    	w = 0;
    	i = 0;
    	n = 0;
    	byte in[4] = {0,0,0,0};
    	while (*from != '\0' && *from != '=' ) {
    		if (*from == ' ' || *from == '\n') {
    			++from;
    			continue;
    		}
    		in[i] = base64_to_sixtet[* (unsigned char *) from];
    		++i;
    		++from;
    		if (*from == '\0' || *from == '=' || i == 4) {
    			w = IntForSixtets( in );
    			for (j = 0; j*8 < i*6; ++j) {
    				*to++ = w & 0xff;
    				++n;
    				w >>= 8;
    			}
    			i = 0;
    			w = 0;
    		}
    	}
    	return n;
    }
    
    /*
    ============
    idBase64::Encode
    ============
    */
    void idBase64::Encode( const idStr &src ) {
    	Encode( (const byte *)src.c_str(), src.Length() );
    }
    
    /*
    ============
    idBase64::Decode
    ============
    */
    void idBase64::Decode( idStr &dest ) const {
    	byte *buf = new byte[ DecodeLength()+1 ]; // +1 for trailing \0
    	int out = Decode( buf );
    	buf[out] = '\0';
    	dest = (const char *)buf;
    	delete[] buf;
    }
    
    /*
    ============
    idBase64::Decode
    ============
    */
    void idBase64::Decode( idFile *dest ) const {	
    	byte *buf = new byte[ DecodeLength()+1 ]; // +1 for trailing \0
    	int out = Decode( buf );
    	dest->Write( buf, out );
    	delete[] buf;
    }
    


  • Schonmal danke dafür 🙂 !

    Leider hat ID sehr viel selbstgemacht (strings, eigenes inline, eigenes filehandle), aber wenn niemand eine schönere Lösung hat werde ich mich wohl ransetzen und die ganzen Datentypen durch standard C++ Datentypen ersetzen 😞



  • Ist keine Arbeit, nur ein wenig find&replace. Die meisten Sachen sind nur typedefs auf Standardkram und ID_INLINE wird wohl ein #define auf inline oder __forceinline sein.



  • na ja wenn man sich

    idFile *dest
    [...]
    dest->Write( buf, out);

    anschaut muss man da doch ein wenig mehr umbiegen als einfach die Datentypen zu ersetzen, aber scheinbar werde ich da nicht herumkommen.

    Eigentlich unverständlich das es keine standard C++ Lösung gibt 😑



  • base schrieb:

    Eigentlich unverständlich das es keine standard C++ Lösung gibt 😑

    Dann mach doch eine. Warum muss immer alles vorgekaut sein?



  • Die Crypto++ Bibliothek besitzt Base64-Konverter: http://www.cryptopp.com
    Ist aufgrund mangelnder Dokumentation allerdings schwierig, den Einstieg zu finden. Für Base64 allein lohnt es sich vielleicht auch nicht. Zumindest aber ist das eine solide C++-Lösung 🙂



  • Walli schrieb:

    base schrieb:

    Eigentlich unverständlich das es keine standard C++ Lösung gibt 😑

    Dann mach doch eine. Warum muss immer alles vorgekaut sein?

    Weil ich, wie bereits geschrieben, keine Lust (ja ich habe keine Lust! Ich will wie bei der STL auf etwas vorgefertigtes zugreifen) und keine Zeit habe.

    Es gibt so viel zu tun, da verwende ich so viel wie möglich aus bereits vorhanden Bibliotheken, nicht jeder der hier Code haben will versucht sich darum zu drücken seine Hausaufgaben machen zu müssen ➡ ⚠



  • base schrieb:

    Es gibt so viel zu tun, da verwende ich so viel wie möglich aus bereits vorhanden Bibliotheken, nicht jeder der hier Code haben will versucht sich darum zu drücken seine Hausaufgaben machen zu müssen ➡ ⚠

    Ja, habe ich auch nicht behauptet. Aber wenn keine Standard-Lösung da ist, dann muss man sich eben schnell eine bestehende an die eigenen Bedürfnisse anpassen oder eben was eigenes machen. Den ID-Code hätte man zumindest in ner Viertelstunde umschreiben können.



  • Hmm. Ich hab da vor ner Weile mal was in C gecodet. Sollte sich ziemlich einfach nach C++ ummodeln lassen; ich poste es einfach mal, für den Fall, dass es jemand brauchen kann:

    #include <ctype.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    char *base64_encode(char *dest, size_t n, char const *src) {
      static char const b64_tbl[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                                    "abcdefghijklmnopqrstuvwxyz"
                                    "0123456789+/";
    
      size_t i, j;
    
      for(i = j = 0; ; i += 4, j += 3) {
        if(src[j]) {
          dest[i    ] = b64_tbl[src[j] >> 2 & 0x3f];
          dest[i + 1] = b64_tbl[((src[j    ] << 4 & 0x30) |
                                 (src[j + 1] >> 4 & 0x0f)) & 0x3f];
        } else {
          dest[i] = '\0';
          break;
        }
    
        if(i >= n - 5)
          return NULL;
    
        if(src[j + 1]) {
          dest[i + 2] = b64_tbl[((src[j + 1] & 0x0f) << 2 |
                                 (src[j + 2] & 0xc0) >> 6) & 0x3f];
        } else {
          dest[i + 2] = dest[i + 3] = '=';
          dest[i + 4] = '\0';
          break;
        }
        if(src[j + 2]) {
          dest[i + 3] = b64_tbl[src[j + 2] & 0x3f];
        } else {
          dest[i + 3] = '=';
          dest[i + 4] = '\0';
          break;
        }
      };
    
      return dest;
    }
    
    static char base64_char_decode(char c) {
      if(islower(c))
        return c - 'a' + 26;
      if(isupper(c))
        return c - 'A';
      if(isdigit(c))
        return c - '0' + 52;
      if(c == '+')
        return 62;
      if(c == '/')
        return 63;
    
      /* Das ist zwar das selbe wie bei 'A', und von daher als Fehlermeldung
       * ungeeignet, aber diese Funktion ist eh nur intern gedacht, und das
       * hier _sollte_ nur auftreten, wenn c == '='. In dem Fall füllt
       * base64_decode halt einfach mit '\0' auf, was den String terminiert
       * und uns alle glücklich macht.
       */
      return 0;
    }
    
    char *base64_decode(char *dest, size_t n, char const *src) {
      size_t i, j;
      char c, d, e, f;
    
      i = strlen(src);
      if(i % 4 != 0 || i / 4 * 3 > n - 1)
        return NULL;
    
      for(i = j = 0; src[j]; i += 3, j += 4) {
        c = base64_char_decode(src[j    ]);
        d = base64_char_decode(src[j + 1]);
        e = base64_char_decode(src[j + 2]);
        f = base64_char_decode(src[j + 3]);
        dest[i    ] = (c << 2) | (d >> 4 & 0x03);
        dest[i + 1] = (d << 4) | (e >> 2 & 0x0f);
        dest[i + 2] = (e << 6) | f;
      }
      dest[i] = '\0';
    
      return dest;
    }
    

    Ist im Grunde immer drei byte von Hand gemangelt. Ich hab mich dabei im Wesentlichen nach der ERklärung auf http://de.wikipedia.org/wiki/Base64 gerichtet. Gut, es ließe sich bestimmt noch an der einen oder anderen Ecke was optimieren, aber es funktioniert, und ich finds eigentlich ziemlich übersichtlich.



  • Frage am rande und sorry das ich den Thread wieder rausgeholt habe, aber wofür benötigt man sowas? 😕



  • CDU Wähler brauchen sowas nicht.



  • Damit kannst du einen String verschlüsselt... mehr muss man nicht sagen, oder?

    Und wofür? Naja, wenn du halt mal Daten hast, die ein anderer nicht lesen können soll (zumindest nicht auf Anhieb, für wirklich vertrauliche Sachen ist Base64 dann längst zu unsicher)...



  • Reyx schrieb:

    Damit kannst du einen String verschlüsselt...

    Nein, als Verschlüsselung ist es nicht zu gebrauchen. Mit Base64 kann man Binärdaten auf den ASCII Zeichensatz abbilden u.a. zur Übertragung mit Protokollen, die nur Textinhalte zulassen.


Log in to reply