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
"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
John Walker
Steve Williams
Ethan Young
+ Edward Flick
GNU GENERAL PUBLIC LICENSE
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
# 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
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 \
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
--- /dev/null
+libb64: Base64 Encoding/Decoding Routines
+======================================
+
+Authors:
+-------
+
+Chris Venter chris.venter@gmail.com http://rocketpod.blogspot.com
--- /dev/null
+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
--- /dev/null
+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.
--- /dev/null
+/*
+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;
+}
+
--- /dev/null
+/*
+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 */
--- /dev/null
+/*
+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;
+}
+
--- /dev/null
+/*
+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 */
#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
*
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);
+ }
+}
/*
*/
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);
}