BASE64 de/encoding - by Edward Flick - replace John Walkers implementation with http...
authorWilfried Goesgens <dothebart@citadel.org>
Thu, 2 Jan 2014 23:08:45 +0000 (00:08 +0100)
committerWilfried Goesgens <dothebart@citadel.org>
Thu, 2 Jan 2014 23:08:45 +0000 (00:08 +0100)
libcitadel/COPYING
libcitadel/Makefile.in
libcitadel/lib/b64/AUTHORS [new file with mode: 0644]
libcitadel/lib/b64/LICENSE [new file with mode: 0644]
libcitadel/lib/b64/README [new file with mode: 0644]
libcitadel/lib/b64/cdecode.c [new file with mode: 0644]
libcitadel/lib/b64/cdecode.h [new file with mode: 0644]
libcitadel/lib/b64/cencode.c [new file with mode: 0644]
libcitadel/lib/b64/cencode.h [new file with mode: 0644]
libcitadel/lib/tools.c

index 41698e9..2018a52 100644 (file)
@@ -1,5 +1,5 @@
 LibCitadel is distributed under the GPL V3. It contains a copy of
-two other modules: 
+three other modules: 
   * xdgmime; http://www.freedesktop.org s xdgmime library in 
     lib/xdgmime, which is distributed under LGPL V2 (or later) or the 
     Academic Free License, version 2.0
@@ -14,6 +14,10 @@ two other modules:
     "You may use this  code any way you wish, private, educational, 
      commercial.  It's free."
 
+  * libb64, http://libb64.sourceforge.net/; rapid base64 en/decode
+    library, which is public domain, courtesy of
+    Chris Venter : chris.venter[anti-spam]gmail.com : http://man9.wordpress.com
+
 LibCitadel is courtesy of the citadel development team:
    Clint Adams
    Steven M. Bellovin
@@ -36,6 +40,7 @@ LibCitadel is courtesy of the citadel development team:
    John Walker
    Steve Williams
    Ethan Young
+   Edward Flick
 
 
                      GNU GENERAL PUBLIC LICENSE
index 924384f..5aa2223 100755 (executable)
@@ -65,8 +65,8 @@ install-pkgconfigDATA: $(pkgconfig_DATA)
 clean:
        echo "Cleaning: $(LIBRARY) *.o *.lo *.gcda *.gcov *.gcno"
        cd lib && rm -f $(LIBRARY) *.o *.lo *.gcda *.gcov *.gcno
-       echo "Cleaning: $(LIBRARY) .libs _libs xdgmime/*.o xdgmime/*.lo xdgmime/.libs xdgmime/*.gcda xdgmime/*.gcov xdgmime/*.gcno"
-       cd lib && rm -rf .libs _libs xdgmime/*.o xdgmime/*.lo xdgmime/.libs xdgmime/*.gcda xdgmime/*.gcov xdgmime/*.gcno
+       echo "Cleaning: $(LIBRARY) .libs _libs b64/*.o b64/*.lo b64/.libs b64/*.gcda b64/*.gcov b64/*.gcno xdgmime/*.o xdgmime/*.lo xdgmime/.libs xdgmime/*.gcda xdgmime/*.gcov xdgmime/*.gcno"
+       cd lib && rm -rf .libs _libs b64/*.o b64/*.lo b64/.libs b64/*.gcda b64/*.gcov b64/*.gcno xdgmime/*.o xdgmime/*.lo xdgmime/.libs xdgmime/*.gcda xdgmime/*.gcov xdgmime/*.gcno
        rm -rf .libs libcitadel.la
 
 clobber: clean
@@ -86,7 +86,7 @@ uninstall:
 
 # for VPATH builds (invoked by configure)
 mkdir-init:
-       @for d in lib lib/xdgmime tests ; do \
+       @for d in lib lib/xdgmime lib/b64 tests ; do \
                (mkdir $$d 2> /dev/null || test 1) ; \
        done
 
@@ -122,6 +122,8 @@ LIB_OBJS = lib/libcitadel.lo \
        lib/json.lo \
        lib/wildfire.lo \
        lib/urlhandling.lo \
+       lib/b64/cencode.lo \
+       lib/b64/cdecode.lo \
        lib/xdgmime/xdgmime.lo \
        lib/xdgmime/xdgmimeglob.lo \
        lib/xdgmime/xdgmimeint.lo \
@@ -143,6 +145,8 @@ lib/lookup3.lo: lib/lookup3.c lib/libcitadel.h
 lib/hash.lo: lib/hash.c lib/libcitadel.h
 lib/json.lo: lib/json.c lib/libcitadel.h
 lib/wildfire.lo: lib/wildfire.c lib/libcitadel.h
+lib/b64/cencode.lo: lib/b64/cencode.c 
+lib/b64/cdecode.lo: lib/b64/cdecode.c
 lib/xdgmime/xdgmime.lo: lib/xdgmime/xdgmime.c 
 lib/xdgmime/xdgmimeglob.lo:  lib/xdgmime/xdgmimeglob.c 
 lib/xdgmime/xdgmimeint.lo:  lib/xdgmime/xdgmimeint.c 
diff --git a/libcitadel/lib/b64/AUTHORS b/libcitadel/lib/b64/AUTHORS
new file mode 100644 (file)
index 0000000..af68737
--- /dev/null
@@ -0,0 +1,7 @@
+libb64: Base64 Encoding/Decoding Routines
+======================================
+
+Authors:
+-------
+
+Chris Venter   chris.venter@gmail.com  http://rocketpod.blogspot.com
diff --git a/libcitadel/lib/b64/LICENSE b/libcitadel/lib/b64/LICENSE
new file mode 100644 (file)
index 0000000..a6b5606
--- /dev/null
@@ -0,0 +1,29 @@
+Copyright-Only Dedication (based on United States law) 
+or Public Domain Certification
+
+The person or persons who have associated work with this document (the
+"Dedicator" or "Certifier") hereby either (a) certifies that, to the best of
+his knowledge, the work of authorship identified is in the public domain of the
+country from which the work is published, or (b) hereby dedicates whatever
+copyright the dedicators holds in the work of authorship identified below (the
+"Work") to the public domain. A certifier, moreover, dedicates any copyright
+interest he may have in the associated work, and for these purposes, is
+described as a "dedicator" below.
+
+A certifier has taken reasonable steps to verify the copyright status of this
+work. Certifier recognizes that his good faith efforts may not shield him from
+liability if in fact the work certified is not in the public domain.
+
+Dedicator makes this dedication for the benefit of the public at large and to
+the detriment of the Dedicator's heirs and successors. Dedicator intends this
+dedication to be an overt act of relinquishment in perpetuity of all present
+and future rights under copyright law, whether vested or contingent, in the
+Work. Dedicator understands that such relinquishment of all rights includes
+the relinquishment of all rights to enforce (by lawsuit or otherwise) those
+copyrights in the Work.
+
+Dedicator recognizes that, once placed in the public domain, the Work may be
+freely reproduced, distributed, transmitted, used, modified, built upon, or
+otherwise exploited by anyone for any purpose, commercial or non-commercial,
+and in any way, including by methods that have not yet been invented or
+conceived.
\ No newline at end of file
diff --git a/libcitadel/lib/b64/README b/libcitadel/lib/b64/README
new file mode 100644 (file)
index 0000000..be93b7b
--- /dev/null
@@ -0,0 +1,138 @@
+b64: Base64 Encoding/Decoding Routines
+======================================
+
+Overview:
+--------
+libb64 is a library of ANSI C routines for fast encoding/decoding data into and
+from a base64-encoded format. C++ wrappers are included, as well as the source
+code for standalone encoding and decoding executables.
+
+base64 consists of ASCII text, and is therefore a useful encoding for storing 
+binary data in a text file, such as xml, or sending binary data over text-only
+email.
+
+References:
+----------
+* Wikipedia article:
+       http://en.wikipedia.org/wiki/Base64
+* base64, another implementation of a commandline en/decoder:
+       http://www.fourmilab.ch/webtools/base64/
+
+Why?
+---
+I did this because I need an implementation of base64 encoding and decoding,
+without any licensing problems. Most OS implementations are released under
+either the GNU/GPL, or a BSD-variant, which is not what I require.
+
+Also, the chance to actually use the co-routine implementation in code is rare,
+and its use here is fitting. I couldn't pass up the chance.
+For more information on this technique, see "Coroutines in C", by Simon Tatham,
+which can be found online here: 
+http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
+
+So then, under which license do I release this code? On to the next section...
+
+License:
+-------
+This work is released under into the Public Domain.
+It basically boils down to this: I put this work in the public domain, and you
+can take it and do whatever you want with it.
+
+An example of this "license" is the Creative Commons Public Domain License, a
+copy of which can be found in the LICENSE file, and also online at
+http://creativecommons.org/licenses/publicdomain/
+
+Commandline Use:
+---------------
+There is a new executable available, it is simply called base64.
+It can encode and decode files, as instructed by the user.
+
+To encode a file:
+$ ./base64 -e filea fileb
+fileb will now be the base64-encoded version of filea.
+
+To decode a file:
+$ ./base64 -d fileb filec
+filec will now be identical to filea.
+
+Programming:
+-----------
+Some C++ wrappers are provided as well, so you don't have to get your hands
+dirty. Encoding from standard input to standard output is as simple as
+
+       #include <b64/encode.h>
+       #include <iostream>
+       int main()
+       {
+               base64::encoder E;
+               E.encode(std::cin, std::cout);
+               return 0;
+       }
+
+Both standalone executables and a static library is provided in the package,
+
+Implementation:
+--------------
+It is DAMN fast, if I may say so myself. The C code uses a little trick which
+has been used to implement coroutines, of which one can say that this
+implementation is an example.
+
+(To see how the libb64 codebase compares with some other BASE64 implementations
+available, see the BENCHMARKS file)
+
+The trick involves the fact that a switch-statement may legally cross into
+sub-blocks. A very thorough and enlightening essay on co-routines in C, using
+this method, can be found in the above mentioned "Coroutines in C", by Simon
+Tatham: http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
+
+For example, an RLE decompressing routine, adapted from the article:
+1      static int STATE = 0;
+2      static int len, c;
+3      switch (STATE)
+4      {
+5              while (1)
+6              {
+7                      c = getchar();
+8                      if (c == EOF) return EOF;
+9                      if (c == 0xFF) {
+10                             len = getchar();
+11                             c = getchar();
+12                             while (len--)
+13                             {
+14                                     STATE = 0;
+15                                     return c;
+16     case 0:
+17                             }
+18                     } else
+19                             STATE = 1;
+20                             return c;
+21     case 1:
+22                     }
+23             }
+24     }
+
+As can be seen from this example, a coroutine depends on a state variable,
+which it sets directly before exiting (lines 14 and 119). The next time the
+routine is entered, the switch moves control to the specific point directly
+after the previous exit (lines 16 and 21).hands
+
+(As an aside, in the mentioned article the combination of the top-level switch,
+the various setting of the state, the return of a value, and the labelling of
+the exit point is wrapped in #define macros, making the structure of the
+routine even clearer.)
+
+The obvious problem with any such routine is the static keyword.
+Any static variables in a function spell doom for multithreaded applications.
+Also, in situations where this coroutine is used by more than one other
+coroutines, the consistency is disturbed.
+
+What is needed is a structure for storing these variabled, which is passed to
+the routine seperately. This obviously breaks the modularity of the function,
+since now the caller has to worry about and care for the internal state of the
+routine (the callee). This allows for a fast, multithreading-enabled
+implementation, which may (obviously) be wrapped in a C++ object for ease of
+use.
+
+The base64 encoding and decoding functionality in this package is implemented
+in exactly this way, providing both a high-speed high-maintanence C interface,
+and a wrapped C++ which is low-maintanence and only slightly less performant.
diff --git a/libcitadel/lib/b64/cdecode.c b/libcitadel/lib/b64/cdecode.c
new file mode 100644 (file)
index 0000000..8f3ff94
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+cdecoder.c - c source to a base64 decoding algorithm implementation
+
+This is part of the libb64 project, and has been placed in the public domain.
+For details, see http://sourceforge.net/projects/libb64
+*/
+
+#include "b64/cdecode.h"
+
+int base64_decode_value(char value_in)
+{
+       static const char decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-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};
+       static const char decoding_size = sizeof(decoding);
+       value_in -= 43;
+       if (value_in < 0 || value_in > decoding_size) return -1;
+       return decoding[(int)value_in];
+}
+
+void base64_init_decodestate(base64_decodestate* state_in)
+{
+       state_in->step = step_a;
+       state_in->plainchar = 0;
+}
+
+int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in)
+{
+       const char* codechar = code_in;
+       char* plainchar = plaintext_out;
+       char fragment;
+       
+       *plainchar = state_in->plainchar;
+       
+       switch (state_in->step)
+       {
+               while (1)
+               {
+       case step_a:
+                       do {
+                               if (codechar == code_in+length_in)
+                               {
+                                       state_in->step = step_a;
+                                       state_in->plainchar = *plainchar;
+                                       return plainchar - plaintext_out;
+                               }
+                               fragment = (char)base64_decode_value(*codechar++);
+                       } while (fragment < 0);
+                       *plainchar    = (fragment & 0x03f) << 2;
+       case step_b:
+                       do {
+                               if (codechar == code_in+length_in)
+                               {
+                                       state_in->step = step_b;
+                                       state_in->plainchar = *plainchar;
+                                       return plainchar - plaintext_out;
+                               }
+                               fragment = (char)base64_decode_value(*codechar++);
+                       } while (fragment < 0);
+                       *plainchar++ |= (fragment & 0x030) >> 4;
+                       *plainchar    = (fragment & 0x00f) << 4;
+       case step_c:
+                       do {
+                               if (codechar == code_in+length_in)
+                               {
+                                       state_in->step = step_c;
+                                       state_in->plainchar = *plainchar;
+                                       return plainchar - plaintext_out;
+                               }
+                               fragment = (char)base64_decode_value(*codechar++);
+                       } while (fragment < 0);
+                       *plainchar++ |= (fragment & 0x03c) >> 2;
+                       *plainchar    = (fragment & 0x003) << 6;
+       case step_d:
+                       do {
+                               if (codechar == code_in+length_in)
+                               {
+                                       state_in->step = step_d;
+                                       state_in->plainchar = *plainchar;
+                                       return plainchar - plaintext_out;
+                               }
+                               fragment = (char)base64_decode_value(*codechar++);
+                       } while (fragment < 0);
+                       *plainchar++   |= (fragment & 0x03f);
+               }
+       }
+       /* control should not reach here */
+       return plainchar - plaintext_out;
+}
+
diff --git a/libcitadel/lib/b64/cdecode.h b/libcitadel/lib/b64/cdecode.h
new file mode 100644 (file)
index 0000000..d0d7f48
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+cdecode.h - c header for a base64 decoding algorithm
+
+This is part of the libb64 project, and has been placed in the public domain.
+For details, see http://sourceforge.net/projects/libb64
+*/
+
+#ifndef BASE64_CDECODE_H
+#define BASE64_CDECODE_H
+
+typedef enum
+{
+       step_a, step_b, step_c, step_d
+} base64_decodestep;
+
+typedef struct
+{
+       base64_decodestep step;
+       char plainchar;
+} base64_decodestate;
+
+void base64_init_decodestate(base64_decodestate* state_in);
+
+int base64_decode_value(char value_in);
+
+int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in);
+
+#endif /* BASE64_CDECODE_H */
diff --git a/libcitadel/lib/b64/cencode.c b/libcitadel/lib/b64/cencode.c
new file mode 100644 (file)
index 0000000..e440f37
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+cencoder.c - c source to a base64 encoding algorithm implementation
+
+This is part of the libb64 project, and has been placed in the public domain.
+For details, see http://sourceforge.net/projects/libb64
+*/
+
+#include "b64/cencode.h"
+
+void base64_init_encodestate(base64_encodestate* state_in)
+{
+       state_in->step = step_A;
+       state_in->result = 0;
+}
+
+char base64_encode_value(char value_in)
+{
+       static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+       if (value_in > 63) return '=';
+       return encoding[(int)value_in];
+}
+
+int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in)
+{
+       const char* plainchar = plaintext_in;
+       const char* const plaintextend = plaintext_in + length_in;
+       char* codechar = code_out;
+       char result;
+       char fragment;
+       
+       result = state_in->result;
+       
+       switch (state_in->step)
+       {
+               while (1)
+               {
+       case step_A:
+                       if (plainchar == plaintextend)
+                       {
+                               state_in->result = result;
+                               state_in->step = step_A;
+                               return codechar - code_out;
+                       }
+                       fragment = *plainchar++;
+                       result = (fragment & 0x0fc) >> 2;
+                       *codechar++ = base64_encode_value(result);
+                       result = (fragment & 0x003) << 4;
+       case step_B:
+                       if (plainchar == plaintextend)
+                       {
+                               state_in->result = result;
+                               state_in->step = step_B;
+                               return codechar - code_out;
+                       }
+                       fragment = *plainchar++;
+                       result |= (fragment & 0x0f0) >> 4;
+                       *codechar++ = base64_encode_value(result);
+                       result = (fragment & 0x00f) << 2;
+       case step_C:
+                       if (plainchar == plaintextend)
+                       {
+                               state_in->result = result;
+                               state_in->step = step_C;
+                               return codechar - code_out;
+                       }
+                       fragment = *plainchar++;
+                       result |= (fragment & 0x0c0) >> 6;
+                       *codechar++ = base64_encode_value(result);
+                       result  = (fragment & 0x03f) >> 0;
+                       *codechar++ = base64_encode_value(result);
+               }
+       }
+       /* control should not reach here */
+       return codechar - code_out;
+}
+
+int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
+{
+       char* codechar = code_out;
+       
+       switch (state_in->step)
+       {
+       case step_B:
+               *codechar++ = base64_encode_value(state_in->result);
+               *codechar++ = '=';
+               *codechar++ = '=';
+               break;
+       case step_C:
+               *codechar++ = base64_encode_value(state_in->result);
+               *codechar++ = '=';
+               break;
+       case step_A:
+               break;
+       }
+       *codechar++ = '\n';
+       
+       return codechar - code_out;
+}
+
diff --git a/libcitadel/lib/b64/cencode.h b/libcitadel/lib/b64/cencode.h
new file mode 100644 (file)
index 0000000..c1e3464
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+cencode.h - c header for a base64 encoding algorithm
+
+This is part of the libb64 project, and has been placed in the public domain.
+For details, see http://sourceforge.net/projects/libb64
+*/
+
+#ifndef BASE64_CENCODE_H
+#define BASE64_CENCODE_H
+
+typedef enum
+{
+       step_A, step_B, step_C
+} base64_encodestep;
+
+typedef struct
+{
+       base64_encodestep step;
+       char result;
+       int stepcount;
+} base64_encodestate;
+
+void base64_init_encodestate(base64_encodestate* state_in);
+
+char base64_encode_value(char value_in);
+
+int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in);
+
+int base64_encode_blockend(char* code_out, base64_encodestate* state_in);
+
+#endif /* BASE64_CENCODE_H */
index df2f1b4..d539619 100644 (file)
@@ -30,6 +30,8 @@
 #include <sys/stat.h>
 #include <errno.h>
 #include <limits.h>
+#include "b64/cencode.h"
+#include "b64/cdecode.h"
 
 #if TIME_WITH_SYS_TIME
 # include <sys/time.h>
 
 typedef unsigned char byte;          /* Byte type */
 
-/* Base64 encoding table */
-const byte etable[256] = {
-       65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
-       82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103,
-       104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
-       118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43,
-       47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-/* Base64 decoding table */
-const byte dtable[256] = {
-       128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
-       128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
-       128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
-       128, 62, 128, 128, 128, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
-       128, 128, 128, 0, 128, 128, 128, 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, 128, 128, 128,
-       128, 128, 128, 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, 128, 128, 128, 128,
-       128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
-       128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
-       128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
-       128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
-       128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
-       128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
-       128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
-       128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
-       128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
-       128, 128, 0
-};
-
 /*
  * copy a string into a buffer of a known size. abort if we exceed the limits
  *
@@ -323,75 +286,52 @@ unsigned long extract_unsigned_long(const char *source, int parmnum)
                return 0;
 }
 
-
-/*
- * CtdlDecodeBase64() and CtdlEncodeBase64() are adaptations of code by John Walker.
- */
-
 size_t CtdlEncodeBase64(char *dest, const char *source, size_t sourcelen, int linebreaks)
 {
-       int i, hiteof = FALSE;
-       int spos = 0;
-       int dpos = 0;
-       int thisline = 0;
-
-       while (!hiteof) {
-               byte igroup[3], ogroup[4];
-               int c, n;
-
-               igroup[0] = igroup[1] = igroup[2] = 0;
-               for (n = 0; n < 3; n++) {
-                       if (spos >= sourcelen) {
-                               hiteof = TRUE;
-                               break;
-                       }
-                       c = source[spos++];
-                       igroup[n] = (byte) c;
+       // linebreaks at 70 are ugly for base64, since 3 bytes in makes 4 bytes out
+       int breaklength = 68;
+       int readlength = 3 * breaklength / 4;
+
+       int t;
+       int destoffset;
+       int sourceoffset;
+       int sourceremaining;
+
+       base64_encodestate _state;
+
+       base64_init_encodestate(&_state);
+
+       if (linebreaks) {
+               sourceremaining = sourcelen;
+               destoffset = 0;
+               sourceoffset = 0;
+
+               while (sourceremaining > 0) {
+                       destoffset += base64_encode_block(
+                               &(source[sourceoffset]),
+                               (readlength > sourceremaining ? sourceremaining : readlength),
+                               &(dest[destoffset]),
+                               &_state);
+                       sourceoffset += readlength;
+                       sourceremaining -= readlength;
+                       dest[destoffset++] = '\r';
+                       dest[destoffset++] = '\n';
                }
-               if (n > 0) {
-                       ogroup[0] = etable[igroup[0] >> 2];
-                       ogroup[1] =
-                           etable[((igroup[0] & 3) << 4) |
-                                  (igroup[1] >> 4)];
-                       ogroup[2] =
-                           etable[((igroup[1] & 0xF) << 2) |
-                                  (igroup[2] >> 6)];
-                       ogroup[3] = etable[igroup[2] & 0x3F];
-
-                       /*
-                        * Replace characters in output stream with "=" pad
-                        * characters if fewer than three characters were
-                        * read from the end of the input stream. 
-                        */
-
-                       if (n < 3) {
-                               ogroup[3] = '=';
-                               if (n < 2) {
-                                       ogroup[2] = '=';
-                               }
-                       }
-                       for (i = 0; i < 4; i++) {
-                               dest[dpos++] = ogroup[i];
-                               dest[dpos] = 0;
-                       }
-                       thisline += 4;
-                       if ( (linebreaks) && (thisline > 70) ) {
-                               dest[dpos++] = '\r';
-                               dest[dpos++] = '\n';
-                               dest[dpos] = 0;
-                               thisline = 0;
-                       }
+
+               t = destoffset;
+               destoffset += base64_encode_blockend(&(dest[destoffset]), &_state);
+               if (t < destoffset) {
+                       dest[destoffset++] = '\r';
+                       dest[destoffset++] = '\n';
                }
-       }
-       if ( (linebreaks) && (thisline > 70) ) {
-               dest[dpos++] = '\r';
-               dest[dpos++] = '\n';
-               dest[dpos] = 0;
-       }
+               return destoffset;
 
-       return(dpos);
-}
+       } else {
+               destoffset = base64_encode_block(source, sourcelen, dest, &_state);
 
+               return destoffset + base64_encode_blockend(&(dest[destoffset]), &_state);
+       }
+}
 
 
 /* 
@@ -400,45 +340,11 @@ size_t CtdlEncodeBase64(char *dest, const char *source, size_t sourcelen, int li
  */
 int CtdlDecodeBase64(char *dest, const char *source, size_t length)
 {
-    int i, c;
-    int dpos = 0;
-    int spos = 0;
-
-    while (TRUE) {
-       byte a[4], b[4], o[3];
-
-       for (i = 0; i < 4; i++) {
-           if (spos >= length) {
-               return(dpos);
-           }
-           c = source[spos++];
-
-           if (c == 0) {
-               if (i > 0) {
-                   return(dpos);
-               }
-               return(dpos);
-           }
-           if (dtable[c] & 0x80) {
-               /* Ignoring errors: discard invalid character. */
-               i--;
-               continue;
-           }
-           a[i] = (byte) c;
-           b[i] = (byte) dtable[c];
-       }
-       o[0] = (b[0] << 2) | (b[1] >> 4);
-       o[1] = (b[1] << 4) | (b[2] >> 2);
-       o[2] = (b[2] << 6) | b[3];
-        i = a[2] == '=' ? 1 : (a[3] == '=' ? 2 : 3);
-       if (i>=1) dest[dpos++] = o[0];
-       if (i>=2) dest[dpos++] = o[1];
-       if (i>=3) dest[dpos++] = o[2];
-       dest[dpos] = 0;
-       if (i < 3) {
-           return(dpos);
-       }
-    }
+       base64_decodestate _state;
+
+       base64_init_decodestate(&_state);
+
+       return base64_decode_block(source, length, dest, &_state);
 }