From 4032a9c4c69d6bec1cf7ed922f869d76617487ae Mon Sep 17 00:00:00 2001 From: Wilfried Goesgens Date: Fri, 3 Jan 2014 00:08:45 +0100 Subject: [PATCH] BASE64 de/encoding - by Edward Flick - replace John Walkers implementation with http://libb64.sourceforge.net which has proven to be a lot faster. --- libcitadel/COPYING | 7 +- libcitadel/Makefile.in | 10 +- libcitadel/lib/b64/AUTHORS | 7 ++ libcitadel/lib/b64/LICENSE | 29 ++++++ libcitadel/lib/b64/README | 138 +++++++++++++++++++++++++ libcitadel/lib/b64/cdecode.c | 88 ++++++++++++++++ libcitadel/lib/b64/cdecode.h | 28 ++++++ libcitadel/lib/b64/cencode.c | 99 ++++++++++++++++++ libcitadel/lib/b64/cencode.h | 31 ++++++ libcitadel/lib/tools.c | 188 +++++++++-------------------------- 10 files changed, 480 insertions(+), 145 deletions(-) create mode 100644 libcitadel/lib/b64/AUTHORS create mode 100644 libcitadel/lib/b64/LICENSE create mode 100644 libcitadel/lib/b64/README create mode 100644 libcitadel/lib/b64/cdecode.c create mode 100644 libcitadel/lib/b64/cdecode.h create mode 100644 libcitadel/lib/b64/cencode.c create mode 100644 libcitadel/lib/b64/cencode.h diff --git a/libcitadel/COPYING b/libcitadel/COPYING index 41698e90b..2018a5281 100644 --- a/libcitadel/COPYING +++ b/libcitadel/COPYING @@ -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 diff --git a/libcitadel/Makefile.in b/libcitadel/Makefile.in index 924384f48..5aa222352 100755 --- a/libcitadel/Makefile.in +++ b/libcitadel/Makefile.in @@ -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 index 000000000..af6873756 --- /dev/null +++ b/libcitadel/lib/b64/AUTHORS @@ -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 index 000000000..a6b56069e --- /dev/null +++ b/libcitadel/lib/b64/LICENSE @@ -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 index 000000000..be93b7b42 --- /dev/null +++ b/libcitadel/lib/b64/README @@ -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 + #include + 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 index 000000000..8f3ff9493 --- /dev/null +++ b/libcitadel/lib/b64/cdecode.c @@ -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 index 000000000..d0d7f489d --- /dev/null +++ b/libcitadel/lib/b64/cdecode.h @@ -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 index 000000000..e440f3784 --- /dev/null +++ b/libcitadel/lib/b64/cencode.c @@ -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 index 000000000..c1e3464af --- /dev/null +++ b/libcitadel/lib/b64/cencode.h @@ -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 */ diff --git a/libcitadel/lib/tools.c b/libcitadel/lib/tools.c index df2f1b42d..d5396191a 100644 --- a/libcitadel/lib/tools.c +++ b/libcitadel/lib/tools.c @@ -30,6 +30,8 @@ #include #include #include +#include "b64/cencode.h" +#include "b64/cdecode.h" #if TIME_WITH_SYS_TIME # include @@ -50,45 +52,6 @@ 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); } -- 2.30.2