]>
Commit | Line | Data |
---|---|---|
ac313345 | 1 | /* |
2 | * This is part of the libb64 project, and has been placed in the public domain. | |
3 | * For details, see http://sourceforge.net/projects/libb64 | |
4 | */ | |
5 | ||
5b4f4e62 DL |
6 | #ifdef HAVE_CONFIG_H |
7 | #include "config.h" | |
8 | #endif | |
9 | ||
ac313345 | 10 | #include "base64.h" |
11 | ||
12 | static const int CHARS_PER_LINE = 72; | |
13 | static const char *ENCODING = | |
14 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | |
15 | ||
16 | void base64_init_encodestate(struct base64_encodestate *state_in) | |
17 | { | |
18 | state_in->step = step_A; | |
19 | state_in->result = 0; | |
20 | state_in->stepcount = 0; | |
21 | } | |
22 | ||
23 | char base64_encode_value(char value_in) | |
24 | { | |
25 | if (value_in > 63) | |
26 | return '='; | |
27 | return ENCODING[(int)value_in]; | |
28 | } | |
29 | ||
30 | int base64_encode_block(const char *plaintext_in, int length_in, char *code_out, | |
31 | struct base64_encodestate *state_in) | |
32 | { | |
33 | const char *plainchar = plaintext_in; | |
34 | const char *const plaintextend = plaintext_in + length_in; | |
35 | char *codechar = code_out; | |
36 | char result; | |
37 | char fragment; | |
38 | ||
39 | result = state_in->result; | |
40 | ||
41 | switch (state_in->step) { | |
42 | while (1) { | |
43 | case step_A: | |
44 | if (plainchar == plaintextend) { | |
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 | /* fall through */ | |
54 | case step_B: | |
55 | if (plainchar == plaintextend) { | |
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 | /* fall through */ | |
65 | case step_C: | |
66 | if (plainchar == plaintextend) { | |
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 | ++(state_in->stepcount); | |
78 | if (state_in->stepcount == CHARS_PER_LINE/4) { | |
79 | *codechar++ = '\n'; | |
80 | state_in->stepcount = 0; | |
81 | } | |
82 | } | |
83 | } | |
84 | /* control should not reach here */ | |
85 | return codechar - code_out; | |
86 | } | |
87 | ||
88 | int base64_encode_blockend(char *code_out, struct base64_encodestate *state_in) | |
89 | { | |
90 | char *codechar = code_out; | |
91 | ||
92 | switch (state_in->step) { | |
93 | case step_B: | |
94 | *codechar++ = base64_encode_value(state_in->result); | |
95 | *codechar++ = '='; | |
96 | *codechar++ = '='; | |
97 | break; | |
98 | case step_C: | |
99 | *codechar++ = base64_encode_value(state_in->result); | |
100 | *codechar++ = '='; | |
101 | break; | |
102 | case step_A: | |
103 | break; | |
104 | } | |
105 | *codechar++ = '\n'; | |
106 | ||
107 | return codechar - code_out; | |
108 | } | |
109 | ||
110 | ||
111 | signed char base64_decode_value(signed char value_in) | |
112 | { | |
113 | static const signed char decoding[] = { | |
114 | 62, -1, -1, -1, 63, 52, 53, 54, | |
115 | 55, 56, 57, 58, 59, 60, 61, -1, | |
116 | -1, -1, -2, -1, -1, -1, 0, 1, | |
117 | 2, 3, 4, 5, 6, 7, 8, 9, | |
118 | 10, 11, 12, 13, 14, 15, 16, 17, | |
119 | 18, 19, 20, 21, 22, 23, 24, 25, | |
120 | -1, -1, -1, -1, -1, -1, 26, 27, | |
121 | 28, 29, 30, 31, 32, 33, 34, 35, | |
122 | 36, 37, 38, 39, 40, 41, 42, 43, | |
123 | 44, 45, 46, 47, 48, 49, 50, 51 | |
124 | }; | |
125 | value_in -= 43; | |
126 | if (value_in < 0 || value_in >= 80) | |
127 | return -1; | |
128 | return decoding[(int)value_in]; | |
129 | } | |
130 | ||
131 | void base64_init_decodestate(struct base64_decodestate *state_in) | |
132 | { | |
133 | state_in->step = step_a; | |
134 | state_in->plainchar = 0; | |
135 | } | |
136 | ||
137 | int base64_decode_block(const char *code_in, int length_in, char *plaintext_out, | |
138 | struct base64_decodestate *state_in) | |
139 | { | |
140 | const char *codec = code_in; | |
141 | char *plainc = plaintext_out; | |
142 | signed char fragmt; | |
143 | ||
144 | *plainc = state_in->plainchar; | |
145 | ||
146 | switch (state_in->step) { | |
147 | while (1) { | |
148 | case step_a: | |
149 | do { | |
150 | if (codec == code_in+length_in) { | |
151 | state_in->step = step_a; | |
152 | state_in->plainchar = *plainc; | |
153 | return plainc - plaintext_out; | |
154 | } | |
155 | fragmt = base64_decode_value(*codec++); | |
156 | } while (fragmt < 0); | |
157 | *plainc = (fragmt & 0x03f) << 2; | |
158 | /* fall through */ | |
159 | case step_b: | |
160 | do { | |
161 | if (codec == code_in+length_in) { | |
162 | state_in->step = step_b; | |
163 | state_in->plainchar = *plainc; | |
164 | return plainc - plaintext_out; | |
165 | } | |
166 | fragmt = base64_decode_value(*codec++); | |
167 | } while (fragmt < 0); | |
168 | *plainc++ |= (fragmt & 0x030) >> 4; | |
169 | *plainc = (fragmt & 0x00f) << 4; | |
170 | /* fall through */ | |
171 | case step_c: | |
172 | do { | |
173 | if (codec == code_in+length_in) { | |
174 | state_in->step = step_c; | |
175 | state_in->plainchar = *plainc; | |
176 | return plainc - plaintext_out; | |
177 | } | |
178 | fragmt = base64_decode_value(*codec++); | |
179 | } while (fragmt < 0); | |
180 | *plainc++ |= (fragmt & 0x03c) >> 2; | |
181 | *plainc = (fragmt & 0x003) << 6; | |
182 | /* fall through */ | |
183 | case step_d: | |
184 | do { | |
185 | if (codec == code_in+length_in) { | |
186 | state_in->step = step_d; | |
187 | state_in->plainchar = *plainc; | |
188 | return plainc - plaintext_out; | |
189 | } | |
190 | fragmt = base64_decode_value(*codec++); | |
191 | } while (fragmt < 0); | |
192 | *plainc++ |= (fragmt & 0x03f); | |
193 | } | |
194 | } | |
195 | /* control should not reach here */ | |
196 | return plainc - plaintext_out; | |
197 | } |