Removed libb64's behavior of automatically appending a newline to everything
[citadel.git] / libcitadel / lib / b64 / cencode.c
1 // 
2 // cencoder.c - c source to a base64 encoding algorithm implementation
3 // 
4 // This is part of the libb64 project, and has been placed in the public domain.
5 // For details, see http://sourceforge.net/projects/libb64
6 // 
7 // ** NOTE: MODIFIED BY AJC 2016JAN22 **
8 // The libb64 distribution always places a newline at the end of an encoded block.
9 // We have removed that behavior.  If libb64 is updated, make that change again.
10 // 
11 // 
12
13 #include "b64/cencode.h"
14
15 void base64_init_encodestate(base64_encodestate* state_in)
16 {
17         state_in->step = step_A;
18         state_in->result = 0;
19 }
20
21 char base64_encode_value(char value_in)
22 {
23         static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
24         if (value_in > 63) return '=';
25         return encoding[(int)value_in];
26 }
27
28 int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in)
29 {
30         const char* plainchar = plaintext_in;
31         const char* const plaintextend = plaintext_in + length_in;
32         char* codechar = code_out;
33         char result;
34         char fragment;
35         
36         result = state_in->result;
37         
38         switch (state_in->step)
39         {
40                 while (1)
41                 {
42         case step_A:
43                         if (plainchar == plaintextend)
44                         {
45                                 state_in->result = result;
46                                 state_in->step = step_A;
47                                 return codechar - code_out;
48                         }
49                         fragment = *plainchar++;
50                         result = (fragment & 0x0fc) >> 2;
51                         *codechar++ = base64_encode_value(result);
52                         result = (fragment & 0x003) << 4;
53         case step_B:
54                         if (plainchar == plaintextend)
55                         {
56                                 state_in->result = result;
57                                 state_in->step = step_B;
58                                 return codechar - code_out;
59                         }
60                         fragment = *plainchar++;
61                         result |= (fragment & 0x0f0) >> 4;
62                         *codechar++ = base64_encode_value(result);
63                         result = (fragment & 0x00f) << 2;
64         case step_C:
65                         if (plainchar == plaintextend)
66                         {
67                                 state_in->result = result;
68                                 state_in->step = step_C;
69                                 return codechar - code_out;
70                         }
71                         fragment = *plainchar++;
72                         result |= (fragment & 0x0c0) >> 6;
73                         *codechar++ = base64_encode_value(result);
74                         result  = (fragment & 0x03f) >> 0;
75                         *codechar++ = base64_encode_value(result);
76                 }
77         }
78         /* control should not reach here */
79         return codechar - code_out;
80 }
81
82 int base64_encode_blockend(char* code_out, base64_encodestate* state_in, int with_newline)
83 {
84         char* codechar = code_out;
85         
86         switch (state_in->step)
87         {
88         case step_B:
89                 *codechar++ = base64_encode_value(state_in->result);
90                 *codechar++ = '=';
91                 *codechar++ = '=';
92                 break;
93         case step_C:
94                 *codechar++ = base64_encode_value(state_in->result);
95                 *codechar++ = '=';
96                 break;
97         case step_A:
98                 break;
99         }
100         if (with_newline) {                     // added by ajc on 2016jan22, normally citadel doesn't want this
101                 *codechar++ = '\r';
102                 *codechar++ = '\n';
103         }
104         
105         return codechar - code_out;
106 }
107