Index: ChangeLog
===================================================================
--- ChangeLog	(revision 4585)
+++ ChangeLog	(revision 4588)
@@ -3,4 +3,5 @@
 	* Updated VS API (Closes: #54, #3)
 	* Added support for CRC24 (RFC 4880)
+	* Added Base64 support.
 
 v. 0.4beta1 - Mon Nov 01 2010 16:14 CET
Index: include/libroar/base64.h
===================================================================
--- include/libroar/base64.h	(revision 4587)
+++ include/libroar/base64.h	(revision 4588)
@@ -56,7 +56,7 @@
 #define roar_base64_init_decode(state,flags) roar_base64_init((state),(flags))
 
-ssize_t roar_base64_encode(struct roar_base64 * state, void * out, size_t outlen, void * in, size_t inlen, size_t * off, int eof);
+ssize_t roar_base64_encode(struct roar_base64 * state, void * out, size_t outlen, const void * in, size_t inlen, size_t * off, int eof);
 
-ssize_t roar_base64_decode(struct roar_base64 * state, void * out, size_t outlen, void * in, size_t inlen, size_t * off);
+ssize_t roar_base64_decode(struct roar_base64 * state, void * out, size_t outlen, const void * in, size_t inlen, size_t * off);
 
 int roar_base64_is_eof(struct roar_base64 * state);
Index: libroar/base64.c
===================================================================
--- libroar/base64.c	(revision 4587)
+++ libroar/base64.c	(revision 4588)
@@ -71,4 +71,5 @@
 
 static inline void _libroar_base64_encode_block(unsigned char out[4], const unsigned char in[3]) {
+// printf("in={'%c', '%c', '%c'}\n", in[0], in[1], in[2]);
  out[0] = _base64_tab_fw[(in[0] >> 2) & 0x3F];
  out[1] = _base64_tab_fw[(((in[0] & 0x03) << 4) | (in[1] >> 4)) & 0x3F];
@@ -77,10 +78,13 @@
 }
 
-#define _setoff(x) do { if ( off != NULL ) { *off = (x) } } while (0)
-
-ssize_t roar_base64_encode(struct roar_base64 * state, void * out, size_t outlen, void * in, size_t inlen, size_t * off, int eof) {
+#define _setoff(x) do { if ( off != NULL ) { *off = (x); } } while (0)
+
+ssize_t roar_base64_encode(struct roar_base64 * state, void * out, size_t outlen, const void * in, size_t inlen, size_t * off, int eof) {
  struct roar_base64 state_store;
  size_t offset = 0;
  size_t tlen;
+ ssize_t ret = 0;
+ unsigned char * outp;
+ const unsigned char * inp;
 
  if ( inlen && in == NULL )
@@ -94,26 +98,194 @@
   return -1;
 
+ // we can not write anything anyway...
+ if ( outlen < 4 )
+  return 0;
+
  if ( state == NULL ) {
   state = &state_store;
-  roar_base64_init_encode(state);
+  roar_base64_init_encode(state, ROAR_BASE64_FLAG_NONE);
   eof = 1;
  }
 
  if ( state->buflen ) {
-  if ( (state->buflen + inlen) >= 3 ) {
-   tlen = 3 - state->buflen;
-   memcpy(state->buf + state->buflen, in, tlen);
+  tlen = 3 - state->buflen;
+  ROAR_DBG("roar_base64_encode(state=%p,...): Still %llu bytes in state", state, (long long unsigned int)state->buflen);
+  ROAR_DBG("roar_base64_encode(state=%p,...): Need %llu bytes", state, (long long unsigned int)tlen);
+  if ( inlen >= tlen ) {
+   memcpy(state->iobuf + state->buflen, in, tlen);
    offset += tlen;
    in += tlen;
    inlen -= tlen;
+   _libroar_base64_encode_block(out, state->iobuf);
+   out += 4;
+   outlen -= 4;
+   ret += 4;
+   state->buflen = 0;
   } else {
-   memcpy(state->buf + state->buflen, in, inlen);
+   memcpy(state->iobuf + state->buflen, in, inlen);
+   state->buflen += inlen;
    _setoff(inlen);
    return 0;
   }
  }
-}
-
-ssize_t roar_base64_decode(struct roar_base64 * state, void * out, size_t outlen, void * in, size_t inlen, size_t * off);
+
+ for (; inlen >= 3 && outlen >= 4;) {
+  _libroar_base64_encode_block(out, in);
+  ret += 4;
+  out += 4;
+  in  += 3;
+  offset += 3;
+  inlen -= 3;
+  outlen -= 4;
+ }
+
+ // something left?
+ if ( inlen ) {
+  if ( eof ) {
+   if ( outlen >= 4 ) {
+    outp = out;
+    inp  = in;
+    switch (inlen) {
+     case 1:
+       outp[0] = _base64_tab_fw[inp[0] >> 2];
+       outp[1] = _base64_tab_fw[(inp[0] & 0x03) << 4];
+       outp[2] = '=';
+       outp[3] = '=';
+       ret += 4;
+       out += 4;
+       in  += 1;
+       offset += 1;
+       inlen  -= 1;
+       outlen -= 4;
+      break;
+     case 2:
+       outp[0] = _base64_tab_fw[inp[0] >> 2];
+       outp[1] = _base64_tab_fw[(((inp[0] & 0x03) << 4) | (inp[1] >> 4)) & 0x3F];
+       outp[2] = _base64_tab_fw[(((inp[1] & 0x0F) << 2))                 & 0x3F];
+       outp[3] = '=';
+       ret += 4;
+       out += 4;
+       in  += 2;
+       offset += 2;
+       inlen  -= 2;
+       outlen -= 4;
+      break;
+    }
+   }
+  } else {
+   memcpy(state->iobuf, in, inlen);
+   state->buflen = inlen;
+   offset += inlen;
+   in += inlen;
+   inlen -= inlen;
+  }
+ }
+
+ if ( outlen ) {
+  *(char*)out = 0;
+ }
+
+ _setoff(offset);
+
+ return 0;
+}
+
+ssize_t roar_base64_decode(struct roar_base64 * state, void * out, size_t outlen, const void * in, size_t inlen, size_t * off) {
+ struct roar_base64 state_store;
+ ssize_t ret = 0;
+ unsigned char c;
+ int bits;
+ const unsigned char * inp = in;
+ unsigned char * outp = out;
+ size_t offset = 0;
+
+ if ( inlen && in == NULL )
+  return -1;
+
+ if ( outlen && out == NULL )
+  return -1;
+
+ // this test should be removed as soon as those modes are supported.
+ if ( in == NULL || out == NULL )
+  return -1;
+
+ if ( state == NULL ) {
+  state = &state_store;
+  roar_base64_init_encode(state, ROAR_BASE64_FLAG_NONE);
+ }
+
+ if ( state->reglen >= 8 ) {
+  *outp  = (state->reg >> (state->reglen - 8)) & 0xFF;
+  state->reglen -= 8;
+  outp++;
+  outlen--;
+  ret++;
+ }
+
+ if ( state->flags & ROAR_BASE64_FLAG_EOF ) {
+  if ( outlen ) {
+   *outp = 0;
+  }
+  return ret;
+ }
+
+ //printf("state->reglen=%i\n", (int)state->reglen);
+
+ for (; inlen && outlen; ) {
+  c = *inp;
+  inp++;
+  inlen--;
+  offset++;
+
+  if ( c == '=' ) {
+   bits = 0;
+  } else {
+   // hi-bit set chars need to be ignored.
+   if ( (size_t)c > sizeof(_base64_tab_bw) )
+    continue;
+
+   bits = _base64_tab_bw[c];
+
+   // ignore unknown chars.
+   if ( bits == (char)0xFF )
+    continue;
+  }
+
+  state->reg   <<= 6;
+  state->reg    |= bits;
+  state->reglen += 6;
+
+  if ( state->reglen >= 8 ) {
+   *outp  = (state->reg >> (state->reglen - 8)) & 0xFF;
+   state->reglen -= 8;
+   outp++;
+   outlen--;
+   ret++;
+  }
+
+  if ( c == '=' ) {
+   state->flags |= ROAR_BASE64_FLAG_EOF;
+   if ( state->reglen <= 6 ) {
+    state->reglen = 0;
+   }
+   if ( inlen ) {
+    if ( *inp == '=' ) {
+     offset++;
+    }
+   }
+   break;
+  }
+ }
+
+ if ( off != NULL ) {
+  *off = offset;
+ }
+
+ if ( outlen ) {
+  *outp = 0;
+ }
+
+ return ret;
+}
 
 int roar_base64_is_eof(struct roar_base64 * state) {
@@ -121,4 +293,7 @@
   return -1;
 
+ if ( state->reglen >= 8 )
+  return 0;
+
  return !!(state->flags & ROAR_BASE64_FLAG_EOF);
 }
@@ -129,9 +304,9 @@
 
  if ( state->buflen ) {
-  ROAR_WARN("roar_base64_uninit(state=%p): State has bytes left in IO buffer. This is a application error.");
+  ROAR_WARN("roar_base64_uninit(state=%p): State has %i bytes left in IO buffer. This is a application error.", state, state->buflen);
  }
 
  if ( state->reglen ) {
-  ROAR_WARN("roar_base64_uninit(state=%p): State has bits left in decode register. This is a application error.");
+  ROAR_WARN("roar_base64_uninit(state=%p): State has %i bits left in decode register. This is a application error.", state, state->reglen);
  }
 
