#ifndef SML3__BASE64_H
#define SML3__BASE64_H

/* ++++++++++++++++++++
 * +++ Beschreibung +++
 * ++++++++++++++++++++

 Enthaelt Base64-Funktionen
+++ */


/* ++++++++++++++++
 * +++ Beispiel +++
 * ++++++++++++++++

  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <sys/types.h>
  #include <unistd.h>
  #include <errno.h>
  #include <sammel3.h>

  int main(int argc, char **argv) {
    char buf[1024];
    size_t sread;
    struct SML3_base64_block hblock = SML3_BASE64_BLOCK_INITIALIZER;  // blockweise ver-/decoden

    if (argc < 2 || strcmp(argv[1], "-h") == 0) {
      fprintf(stderr, "Aufruf: %s -c:  liest von stdin, vercodet base64 nach stdout.\n", argv[0]);
      fprintf(stderr, "Aufruf: %s -d:  liest von stdin, decodet base64 nach stdout.\n", argv[0]);
      fprintf(stderr, "Aufruf: %s -C:  wie -c fuer Dateinamen.\n", argv[0]);
      fprintf(stderr, "Aufruf: %s -D:  wie -d fuer Dateinamen.\n", argv[0]);
      exit(1);
    }

    if (strcmp(argv[1], "-c") == 0) {
      // nach Base64 vercoden
      const int nlz = 76;  // Newline nach nlz Zeichen
      char *bcode;
      size_t scode;
      while ((sread = fread(buf, 1, sizeof(buf), stdin)) > 0) {
        // bockweise vercoden
        SML3_base64_encode(&bcode, &scode, buf, sread, nlz, &hblock);
        printf("%s", bcode); free(bcode);
      }
      // Rest vercoden
      SML3_base64_encode(&bcode, &scode, NULL, 0, nlz, &hblock);
      printf("%s", bcode); free(bcode);

    } else if (strcmp(argv[1], "-d") == 0) {
      // von Base64 decoden
      char *buncode;
      size_t suncode;
      while ((sread = fread(buf, 1, sizeof(buf), stdin)) > 0) {
        // bockweise decoden
        SML3_base64_decode(&buncode, &suncode, buf, sread, &hblock);
        fwrite(buncode, 1, suncode, stdout); free(buncode);
      }
      // Rest decoden
      SML3_base64_decode(&buncode, &suncode, NULL, 0, &hblock);
      fwrite(buncode, 1, suncode, stdout); free(buncode);

    } else if (strcmp(argv[1], "-C") == 0) {
      // Dateiname vercoden
      if (fgets(buf, sizeof(buf), stdin) != NULL) {
        char fname[512];
        SML3_file64_encode(buf, fname, sizeof(fname));
        printf("%s\n", fname);
      }

    } else if (strcmp(argv[1], "-D") == 0) {
      // Dateiname decoden
      if (fgets(buf, sizeof(buf), stdin) != NULL) {
        char fname[512];
        SML3_file64_decode(buf, fname, sizeof(fname));
        printf("%s\n", fname);
      }
    }

    exit(0);
  }
+++ */


/* ++++++++++++++++++ */
/* +++ Funktionen +++ */
/* ++++++++++++++++++ */

#include <sys/types.h>
#include <string.h>

struct SML3_base64_block {
  int srest;
  union {
    struct {
      int nlz;
      char brest[4];
    } enc;
    struct {
      size_t brest[4];
    } dec;
  } u;
};

/* Initialisierer fuer Hilfsstruct:  SML3_base64_block bh64 = SML3_BASE64_BLOCK_INITIALIZER; */
#define SML3_BASE64_BLOCK_INITIALIZER { 0, {{ 0, ""}} }

/* Re-Initialisierer fuer Hilfsstruct:  SML3_BASE64_BLOCK_REINITIALIZE(&bh64); */
#define SML3_BASE64_BLOCK_REINITIALIZE(P1)  memset((P1), 0, sizeof(struct SML3_base64_block))


/** SML3_base64_encode [thread-sicher]:
 * vercodet nach Base64
 * 1.Arg: fuer Rueckgabe vercodete Daten (wird alloziert), enthaelt Ende-0
 * 2.Arg: fuer Rueckgabe Anzahl Bytes im 1.Arg (ohne Ende-0), oder NULL
 * 3.Arg: zu vercodende Daten
 * 4.Arg: Anzahl Bytes im 3.Arg
 * 5.Arg: Anzahl Zeichen, nach denen Newline eingefuegt werden soll
 *        oder  0 = nie
 *        oder -1 = einmalig am Schluss
 * 6.Arg: Adresse auf Hilfsstruct fuer blockweise Vercodung
 *          (muss anfangs mit SML3_BASE64_BLOCK_INITIALIZER oder SML3_BASE64_BLOCK_REINITIALIZE() initialisiert sein)
 *        oder NULL = Einmalvercodung
 * Bei blockweiser Vercodung muss zum Schluss das Hilfsstruct geleert werden
 * durch Aufruf SML3_base64_encode() und 3.Arg=NULL und 4.Arg=0
 */
extern void SML3_base64_encode(char **, size_t *, const char *, size_t, int, struct SML3_base64_block *);


/** SML3_base64_decode [thread-sicher]:
 * decodet von Base64
 * 1.Arg: fuer Rueckgabe decodete Daten (wird alloziert), enthaelt Ende-0
 * 2.Arg: fuer Rueckgabe Anzahl Bytes im 1.Arg (ohne Ende-0), oder NULL
 * 3.Arg: zu decodende Daten
 * 4.Arg: Anzahl Bytes im 3.Arg
 * 5.Arg: Adresse auf Hilfsstruct fuer blockweise Decodung
 *          (muss anfangs mit SML3_BASE64_BLOCK_INITIALIZER oder SML3_BASE64_BLOCK_REINITIALIZE() initialisiert sein)
 *        oder NULL = Einmaldecodung
 * Bei blockweiser Decodung muss zum Schluss das Hilfsstruct geleert werden
 * durch Aufruf SML3_base64_decode() und 3.Arg=NULL und 4.Arg=0
 */
extern void SML3_base64_decode(char **, size_t *, const char *, size_t, struct SML3_base64_block *);


/** SML3_html64_encode [thread-sicher]:
 * vercodet nach modifiziertem html-faehigen Base64
 * 1.Arg: fuer Rueckgabe vercodete Daten (wird alloziert), enthaelt Ende-0
 * 2.Arg: fuer Rueckgabe Anzahl Bytes im 1.Arg (ohne Ende-0), oder NULL
 * 3.Arg: zu vercodende Daten
 * 4.Arg: Anzahl Bytes im 3.Arg
 * 5.Arg: Adresse auf Hilfsstruct fuer blockweise Vercodung
 *          (muss anfangs mit SML3_BASE64_BLOCK_INITIALIZER oder SML3_BASE64_BLOCK_REINITIALIZE() initialisiert sein)
 *        oder NULL = Einmalvercodung
 * Bei blockweiser Vercodung muss zum Schluss das Hilfsstruct geleert werden
 * durch Aufruf SML3_html64_encode() und 3.Arg=NULL und 4.Arg=0
 */
extern void SML3_html64_encode(char **, size_t *, const char *, size_t, struct SML3_base64_block *);


/** SML3_html64_decode [thread-sicher]:
 * decodet von modifiziertem html-faehigen Base64
 * 1.Arg: fuer Rueckgabe decodete Daten (wird alloziert), enthaelt Ende-0
 * 2.Arg: fuer Rueckgabe Anzahl Bytes im 1.Arg (ohne Ende-0), oder NULL
 * 3.Arg: zu decodende Daten
 * 4.Arg: Anzahl Bytes im 3.Arg
 * 5.Arg: Adresse auf Hilfsstruct fuer blockweise Decodung
 *          (muss anfangs mit SML3_BASE64_BLOCK_INITIALIZER oder SML3_BASE64_BLOCK_REINITIALIZE() initialisiert sein)
 *        oder NULL = Einmaldecodung
 * Bei blockweiser Decodung muss zum Schluss das Hilfsstruct geleert werden
 * durch Aufruf SML3_html64_decode() und 3.Arg=NULL und 4.Arg=0
 */
extern void SML3_html64_decode(char **, size_t *, const char *, size_t, struct SML3_base64_block *);


/** SML3_file64_encode [thread-sicher]:
 * vercodet base64-aehnlich, geeignet fuer Dateinamen
 * 1.Arg: Dateiname
 * 2.Arg: fuer Rueckgabe vercodeter Dateiname
 * 3.Arg: sizeof(2.Arg)
 */
extern void SML3_file64_encode(const char *, char *, size_t);


/** SML3_file64_decode [thread-sicher]:
 * decodet base64-aehnlich, geeignet fuer Dateinamen
 * 1.Arg: Dateiname
 * 2.Arg: fuer Rueckgabe decodeter Dateiname
 * 3.Arg: sizeof(2.Arg)
 */
extern void SML3_file64_decode(const char *, char *, size_t);

#endif /* SML3__BASE64_H */
