Warning: Table './usr_web1030_3/variable' is marked as crashed and should be repaired query: SELECT * FROM variable in /var/www/web1030/html/mkernel.de/includes/database.mysql.inc on line 128

Warning: Cannot modify header information - headers already sent by (output started at /var/www/web1030/html/mkernel.de/includes/database.mysql.inc:128) in /var/www/web1030/html/mkernel.de/includes/bootstrap.inc on line 726

Warning: Cannot modify header information - headers already sent by (output started at /var/www/web1030/html/mkernel.de/includes/database.mysql.inc:128) in /var/www/web1030/html/mkernel.de/includes/bootstrap.inc on line 727

Warning: Cannot modify header information - headers already sent by (output started at /var/www/web1030/html/mkernel.de/includes/database.mysql.inc:128) in /var/www/web1030/html/mkernel.de/includes/bootstrap.inc on line 728

Warning: Cannot modify header information - headers already sent by (output started at /var/www/web1030/html/mkernel.de/includes/database.mysql.inc:128) in /var/www/web1030/html/mkernel.de/includes/bootstrap.inc on line 729
[Coder's Implementation{C}] Base64-Encoding | Drupal

[Coder's Implementation{C}] Base64-Encoding

  • warning: Cannot modify header information - headers already sent by (output started at /var/www/web1030/html/mkernel.de/includes/database.mysql.inc:128) in /var/www/web1030/html/mkernel.de/includes/common.inc on line 148.
  • user warning: Table './usr_web1030_3/variable' is marked as crashed and should be repaired query: UPDATE variable SET value = 'a:17:{i:0;i:62;i:1;i:61;i:2;i:59;i:3;i:31;i:4;i:30;i:5;i:29;i:6;i:24;i:7;i:21;i:8;i:15;i:9;i:14;i:10;i:11;i:11;i:7;i:12;i:6;i:13;i:5;i:14;i:3;i:15;i:2;i:16;i:1;}' WHERE name = 'menu_masks' in /var/www/web1030/html/mkernel.de/includes/bootstrap.inc on line 609.
  • user warning: Table './usr_web1030_3/variable' is marked as crashed and should be repaired query: UPDATE variable SET value = 'a:0:{}' WHERE name = 'menu_expanded' in /var/www/web1030/html/mkernel.de/includes/bootstrap.inc on line 609.
  • user warning: Table './usr_web1030_3/variable' is marked as crashed and should be repaired query: DELETE FROM variable WHERE name = 'menu_rebuild_needed' in /var/www/web1030/html/mkernel.de/includes/bootstrap.inc on line 634.

Wissen gerät in Vergessenheit. Das gilt auch für Technologien und Standards aus dem Softwareumfeld. Eine dieser vom aussterben bedrohten Technologien ist Base64. Es handelt sich dabei um eine Vorschrift, wie man beliebige Binärdaten in ASCII-Daten umwandelt und zurück. Base64 wird seid etwa 1987 eingesetzt. Interessant daran ist, das sie fundamentaler Bestandteil des Internets ist. Sie wird für E-Mails genauso benötigt wie für die Übertragung von Binärdaten per HTTP oder für das ablegen von beliebigen Daten in XML. In Vergessenheit gerät also nicht die Anwendung dieser Technologie, sondern deren Implementierung. Base64 ist so alt, das es auf neue Plattformen schon nicht mehr portiert wird. Genau das hat mich erwischt.

Für ein Projekt benötigte ich XML-RPC auf dem iPhone. XML-RPC setzt wiederum Base64 voraus. Letzteres stand aber nicht zur Verfügung. Da fiel die Wahl des Werkzeugs nicht sonderlich schwer...

Ich habe mich also rangesetzt und angefangen, Base64 "on the ground" zu implementieren, ohne zusätzliche Bibliotheken.

Wie Base64 funktioniert

Base64 enkodiert immer 3 Bytes des Eingangsstroms in 4 Bytes ausgangsstrom, ohne Informationen hinzuzufügen. Es werden also 24 Bit auf 4 Byte verteilt. Dadurch reduziert sich die Anzahl der Bitkombinationen pro Byte auf 63. Das wird über eine Information->ASCII-Zeichen Tabelle gemappt.

Der Datenstrom ist in der Länge aber nicht immer durch 3 Teilbar. Base64 sieht dafür vor, im Ausgangsstrom für die fehlenden Informationen ein Gleichheitszeichen zu hinterlegen. Ich habe mich gefragt, ob durch dieses 3:4-Verhältnis nicht eine Unschärfe in der Datenlänge entsteht beim dekodieren. Dem ist aber nicht so, weil zunächst 24 Bit zusammengesetzt werden und dann die Füllbytes (das =) weggelassen werden, jedoch mit einer Gewichtung von 8Bit. Die 2Bit, die in einem anderen Byte waren, waren ja eh 0, weil sie beim enkodieren ja schon nicht vorhanden waren. Wer es genauer wissen möchte, der Wikipedia Artikel ist sehr gut: http://de.wikipedia.org/wiki/Base64 (PDF).

Ablauf von Base64

Angenommen, die Eingangsparameter sind bereinigt (Ausgangspuffer groß genug, etc.), und der Aufruf sieht so aus (Pseudocode):

bool encodebase64(input,output)

Wie wird enkodiert?
Zunächst wird eine Tabelle benötigt welche die für die Umwandlung der 63 Möglichkeiten in ASCII-Zeichen enthält:

char table[]={'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'};

Da immer 3 Bytes eine Einheit bilden, geht man in Dreierschritten durch den Eingangsstrom. Ausserdem werden immer aus 3 Bytes ein Wert zusammengesetzt. Damit lässt es sich leichter dekodieren. Normalerweise müsste die Datenstromlänge noch berücksichtigt werden. Im folgenden Beispielcode wird von einer durch drei teilbaren Datenstromlänge ausgegangen:

for(i=0;i < input.length; i+=3)
{
int temp=0;
temp=input[i];
temp=temp<<8;
temp=temp|input[i+1];
temp=temp<<8;
temp=temp|input[i+2];

    output.add(table[temp&gt;&gt;18]);
    output.add(table[(temp&gt;&gt;12)&amp;0x3F]);
    output.add(table[(temp)&amp;0x3F]);

}


Schon fertig. Die Logik für unpassende Datenstromlängen fehlt hier, aber das Prinzip wird klar. Zunächst wird in 8Bit-Schritten zusammengesetzt, dann wieder dekodiert, aber in 6Bit-Schritten.

Beim Dekodieren ist der Ablauf ähnlich. jedoch benötigt man die inverse der Tabelle. Der Ablauf dreht sich in den Größen um: 4 Bytes über die Tabelle in einen Wert zusammensetzen, in 6bit-Schritten. Anschließend Byte für Byte in den Ausgangsdatenstrom schreiben.

Code

Das ganze gibt es auch als Xcode-Projekt. Dabei habe ich auf die Datenstromlänge geachtet. Ich benutze zum Lesen von Dateien Funktionen von Mac OS, aber die beiden C-Funktionen für base64 sind absolut Plattformunabhängig. Sie haben keinerlei externe Verweise.

Happy Coding