1 // ----------------------------------------------------------------------------
2 // Copyright (C) 2014
3 //              David Freese, W1HKJ
4 //
5 // This file is part of fldigi
6 //
7 // fldigi is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 3 of the License, or
10 // (at your option) any later version.
11 //
12 // fldigi is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 // ----------------------------------------------------------------------------
20 
21 //=====================================================================
22 //
23 // base64 encoding / decoding class
24 //
25 // To create a standalone base64 encode/coder:
26 // g++ -DTEST b64.cxx -o base64
27 //
28 // To use in a calling program:
29 //
30 // base64 b64;        // default no CRLF's in output file
31 // base 64 b64(true); // insert CRLF's in output file
32 // pass c++ string into encoder / decoder
33 // return value is encoded / decoded string
34 // original string is left unchanged
35 //
36 // string instr, outstr;
37 // outstr = b64.encoder(instr);
38 // outstr = b64.decoder(instr);
39 //=====================================================================
40 
41 #ifdef HAVE_CONFIG_H
42 #  include <config.h>
43 #endif
44 
45 #include "b64.h"
46 
init()47 void base64::init()
48 {
49 	iolen = 0;
50 	iocp = 0;
51 	ateof = false;
52 	linelength = 0;
53 
54 // create the etable for encoding
55 	for (int i = 0; i < 9; i++) {
56 		etable[i] = 'A' + i;
57 		etable[i + 9] = 'J' + i;
58 		etable[26 + i] = 'a' + i;
59 		etable[26 + i + 9] = 'j' + i;
60 	}
61 	for (int i = 0; i < 8; i++) {
62 		etable[i + 18] = 'S' + i;
63 		etable[26 + i + 18] = 's' + i;
64 	}
65 	for (int i = 0; i < 10; i++)
66 		etable[52 + i] = '0' + i;
67 	etable[62] = '+';
68 	etable[63] = '/';
69 
70 // create the dtable for decoding
71 	for (int i= 0; i < 255; i++)
72 		dtable[i] = 0x80;
73 	for (int i = 'A'; i <= 'I'; i++)
74 		dtable[i] = 0 + (i - 'A');
75 	for (int i = 'J'; i <= 'R'; i++)
76 		dtable[i] = 9 + (i - 'J');
77 	for (int i = 'S'; i <= 'Z'; i++)
78 		dtable[i] = 18 + (i - 'S');
79 	for (int i = 'a'; i <= 'i'; i++)
80 		dtable[i] = 26 + (i - 'a');
81 	for (int i = 'j'; i <= 'r'; i++)
82 		dtable[i] = 35 + (i - 'j');
83 	for (int i = 's'; i <= 'z'; i++)
84 		dtable[i] = 44 + (i - 's');
85 	for (int i = '0'; i <= '9'; i++)
86 		dtable[i] = 52 + (i - '0');
87 	dtable[(int)'+'] = 62;
88 	dtable[(int)'/'] = 63;
89 	dtable[(int)'='] = 0;
90 }
91 
encode(std::string in)92 std::string base64::encode(std::string in)
93 {
94 	int n;
95 	byte igroup[3], ogroup[4];
96 
97 	output = "";
98 	iocp = 0;
99 	ateof = false;
100 	if (crlf)
101 		linelength = 0;
102 	iolen = in.length();
103 
104 	while (!ateof) {
105 		igroup[0] = igroup[1] = igroup[2] = 0;
106 		for (n = 0; n < 3; n++) {
107 			if (iocp == iolen) {
108 				ateof = true;
109 				break;
110 			}
111 			igroup[n] = (byte)in[iocp];
112 			iocp++;
113 		}
114  		if (n > 0) {
115 			ogroup[0] = etable[igroup[0] >> 2];
116 			ogroup[1] = etable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
117 			ogroup[2] = etable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
118 			ogroup[3] = etable[igroup[2] & 0x3F];
119 			if (n < 2) {
120 				ogroup[2] = '=';
121 				if (n < 1) {
122 					ogroup[2] = '=';
123 				}
124 			}
125 			for (int i = 0; i < 4; i++) {
126 				if (crlf)
127 					if (linelength >= LINELEN) {
128 //						output += '\r';
129 						output += '\n';
130 						linelength = 0;
131 					}
132 				output += (byte)ogroup[i];
133 				if (crlf)
134 					linelength++;
135 			}
136 		}
137 	}
138 	if (crlf) {
139 //		output += '\r';
140 		output += '\n';
141 	}
142 
143 	return output;
144 }
145 
decode(std::string in)146 std::string base64::decode(std::string in)
147 {
148 	int i;
149 	output = "";
150 	iocp = 0;
151 	iolen = in.length();
152 	byte c;
153 
154 	while (iocp < iolen) {
155 		byte a[4], b[4], o[3];
156 
157 		for (i = 0; i < 4; i++) {
158 			if (iocp == iolen) {
159 				output = "b64 file length error.\n";
160 				return output;
161 			}
162 			c = in[iocp++];
163 			while (c <= ' ') {
164 				if (iocp == iolen) {
165 					return output;
166 				}
167 				c = in[iocp++];
168 			}
169 			if (dtable[c] & 0x80) {
170 				output = "Illegal character in b64 file.\n";
171 				return output;
172 			}
173 			a[i] = c;
174 			b[i] = (byte)dtable[c];
175 		}
176 		o[0] = (b[0] << 2) | (b[1] >> 4);
177 		o[1] = (b[1] << 4) | (b[2] >> 2);
178 		o[2] = (b[2] << 6) | b[3];
179 		output += o[0];
180 		if (a[2] != '=') {
181 			output += o[1];
182 			if (a[3] != '=')
183 				output += o[2];
184 		}
185 	}
186 	return output;
187 }
188 
189 #ifdef TEST
190 #include <iostream>
191 #include <fstream>
192 
193 
usage(void)194 void usage(void)
195 {
196 	printf("b64  --  Encode/decode file as base64.  Call:\n");
197 	printf("         b64 e/d < infile > outfile\n");
198 }
199 
main(int argc,char * argv[])200 int main(int argc,char*argv[])
201 {
202 	char opt;
203 	bool decoding = false;
204 	char * cp;
205 	byte c;
206 
207 	std::string inputstring;
208 	std::string infilename;
209 	std::string outputstring;
210 	std::string outfilename;
211 
212 	base64 b64;
213 
214 	if (argc < 2) {
215 		usage();
216 		return(0);
217 	}
218 	opt = *(argv[1]);
219 
220 	if (opt == 'd' || opt == 'D') {
221 		while (!std::cin.eof()) {
222 			c = std::cin.get();
223 			if (!std::cin.eof())
224 				inputstring += c;
225 		}
226 		outputstring = b64.decode( inputstring );
227 		size_t len = outputstring.length();
228 		for (size_t n = 0; n < len; n++)
229 			std::cout << (unsigned char)outputstring[n];
230 	} else if (opt == 'e' || opt == 'E') {
231 		while (!std::cin.eof()) {
232 			c = std::cin.get();
233 			if (!std::cin.eof())
234 				inputstring += c;
235 		}
236 		outputstring = b64.encode( inputstring );
237 		size_t len = outputstring.length();
238 		for (size_t n = 0; n < len; n++)
239 			std::cout << (unsigned char)outputstring[n];
240 	} else
241 		usage();
242 
243 	return 0;
244 }
245 #endif
246