Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
base64.cpp
Go to the documentation of this file.
1/*
2** Command & Conquer Generals Zero Hour(tm)
3** Copyright 2025 Electronic Arts Inc.
4**
5** This program is free software: you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation, either version 3 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/***********************************************************************************************
20 *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
21 ***********************************************************************************************
22 * *
23 * Project Name : Command & Conquer *
24 * *
25 * $Archive:: /Commando/Code/wwlib/base64.cpp $*
26 * *
27 * $Author:: Jani_p $*
28 * *
29 * $Modtime:: 5/04/01 8:08p $*
30 * *
31 * $Revision:: 3 $*
32 * *
33 *---------------------------------------------------------------------------------------------*
34 * Functions: *
35 * Base64_Decode -- Decodes Base 64 data into its original data form. *
36 * Base64_Encode -- Encode data into Base 64 format. *
37 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
38
39#include "always.h"
40#include "base64.h"
41//#include <stddef.h>
42
43/*
44** This is the magic padding character used to fill out the encoded data to a multiple of
45** 4 characters even though the source data is less than necessary to accomplish this.
46** The pad character lets the decoder know of this condition and it will compensate
47** accordingly.
48*/
49static char const * const _pad = "=";
50
51/*
52** This encoder translation table will convert a 6 bit number into an ASCII character.
53*/
54static char const * const _encoder = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
55
56/*
57** The decoder translation table takes an ASCII character and converts it into a
58** 6 bit number.
59*/
60#define BAD 0xFE // Ignore this character in source data.
61#define END 0xFF // Signifies premature end of input data.
62static unsigned char const _decoder[256] = {
66 52,53,54,55,56,57,58,59,60,61,BAD,BAD,BAD,END,BAD,BAD,
67 BAD,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,
68 15,16,17,18,19,20,21,22,23,24,25,BAD,BAD,BAD,BAD,BAD,
69 BAD,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
70 41,42,43,44,45,46,47,48,49,50,51,BAD,BAD,BAD,BAD,BAD,
79};
80
81int const PacketChars = 4;
82
83
84/*
85** The packet type is used to construct and disect the Base64 data blocks. The data
86** consists of three source data bytes mapped onto four 6 bit Base64 code elements.
87*/
88typedef union {
89 struct {
90#ifdef BIG_ENDIAN
91 unsigned char C1;
92 unsigned char C2;
93 unsigned char C3;
94#else
95 unsigned char C3;
96 unsigned char C2;
97 unsigned char C1;
98#endif
99 unsigned char pad;
101 struct {
102#ifdef BIG_ENDIAN
103 unsigned O1:6;
104 unsigned O2:6;
105 unsigned O3:6;
106 unsigned O4:6;
107#else
108 unsigned O4:6;
109 unsigned O3:6;
110 unsigned O2:6;
111 unsigned O1:6;
112#endif
113 unsigned pad:8;
114 } SubCode;
115 unsigned int Raw;
116} PacketType;
117
118
119/***********************************************************************************************
120 * Base64_Encode -- Encode data into Base 64 format. *
121 * *
122 * This will take an arbitrary length of source data and transform it into base 64 format *
123 * data. Base 64 format has the property of being very portable across text editors and *
124 * country character encoding schemes. As such it is ideal for e-mail. Note that the output *
125 * data will be about 33% larger than the source. *
126 * *
127 * INPUT: source -- Pointer to the source data to convert. *
128 * *
129 * slen -- The number of bytes to encode. *
130 * *
131 * dest -- Pointer to the destination buffer that will hold the encoded data. *
132 * *
133 * dlen -- The size of the destination buffer. *
134 * *
135 * OUTPUT: Returns with the number of bytes stored into the destination buffer. *
136 * *
137 * WARNINGS: Be sure that the destination buffer is big enough to hold the encoded output. *
138 * *
139 * HISTORY: *
140 * 07/06/1996 JLB : Created. *
141 *=============================================================================================*/
142int Base64_Encode(void const * source, int slen, void * dest, int dlen)
143{
144 /*
145 ** Check the parameters for legality.
146 */
147 if (source == NULL || slen == 0 || dest == NULL || dlen == 0) {
148 return(0);
149 }
150
151 /*
152 ** Process the source data in blocks of three bytes. Fewer than three bytes
153 ** results in special padding output characters (automatically discarded
154 ** during the decode process).
155 */
156 int total = 0;
157 unsigned char const * sptr = (unsigned char const *)source;
158 unsigned char * dptr = (unsigned char *)dest;
159 while (slen > 0 && dlen >= PacketChars) {
160
161 /*
162 ** Fetch 24 bits of source data.
163 */
164 PacketType packet;
165
166 int pad = 0;
167 packet.Raw = 0;
168 packet.Char.C1 = *sptr++;
169 slen--;
170 if (slen) {
171 packet.Char.C2 = *sptr++;
172 slen--;
173 } else {
174 pad++;
175 }
176 if (slen) {
177 packet.Char.C3 = *sptr++;
178 slen--;
179 } else {
180 pad++;
181 }
182
183 /*
184 ** Translate and write 4 characters of Base64 data. Pad with pad
185 ** characters if there is insufficient source data for a full packet.
186 */
187 *dptr++ = _encoder[packet.SubCode.O1];
188 *dptr++ = _encoder[packet.SubCode.O2];
189 if (pad < 2) {
190 *dptr++ = _encoder[packet.SubCode.O3];
191 } else {
192 *dptr++ = _pad[0];
193 }
194 if (pad < 1) {
195 *dptr++ = _encoder[packet.SubCode.O4];
196 } else {
197 *dptr++ = _pad[0];
198 }
199
200 dlen -= PacketChars;
201 total += PacketChars;
202 }
203
204 /*
205 ** Add a trailing null as a courtesy measure.
206 */
207 if (dlen > 0) {
208 *dptr = '\0';
209 }
210
211 /*
212 ** Return with the total number of characters in the output buffer.
213 */
214 return(total);
215}
216
217
218/***********************************************************************************************
219 * Base64_Decode -- Decodes Base 64 data into its original data form. *
220 * *
221 * Use this routine to decode base 64 data back into the original data. A property of this *
222 * decode process is that unrecognized input characters are ignored. This allows mangled *
223 * source (filled with line breaks or spaces) to be correctly decoded. The decode process *
224 * terminates when the end of the source data has been reached or the special end of data *
225 * marker is encountered. *
226 * *
227 * INPUT: source -- Pointer to the source data to decode. *
228 * *
229 * slen -- The number of bytes in the source data buffer. *
230 * *
231 * dest -- Pointer to the destination buffer to be filled with the decoded data. *
232 * *
233 * dlen -- The maximum size of the destination buffer. *
234 * *
235 * OUTPUT: Returns with the number of bytes stored into the destination buffer. This will *
236 * always be less than the number of source bytes (usually by about 33%). *
237 * *
238 * WARNINGS: none *
239 * *
240 * HISTORY: *
241 * 07/06/1996 JLB : Created. *
242 *=============================================================================================*/
243int Base64_Decode(void const * source, int slen, void * dest, int dlen)
244{
245 /*
246 ** Check the parameters for legality.
247 */
248 if (source == NULL || slen == 0 || dest == NULL || dlen == 0) {
249 return(0);
250 }
251
252 int total = 0;
253 unsigned char const * sptr = (unsigned char const *)source;
254 unsigned char * dptr = (unsigned char *)dest;
255 while (slen > 0 && dlen > 0) {
256
257 PacketType packet;
258 packet.Raw = 0;
259
260 /*
261 ** Process input until a full packet has been accumulated or the
262 ** source is exhausted.
263 */
264 int pcount = 0;
265 while (pcount < PacketChars && slen > 0) {
266 unsigned char c = *sptr++;
267 slen--;
268
269 unsigned char code = _decoder[c];
270
271 /*
272 ** An unrecognized character is skipped.
273 */
274 if (code == BAD) continue;
275
276 /*
277 ** The "=" character signifies the end of data regardless of what
278 ** the source buffer length value may be.
279 */
280 if (code == END) {
281 slen = 0;
282 break;
283 }
284
285 /*
286 ** A valid Base64 character was found so add it to the packet
287 ** data.
288 */
289 switch (pcount) {
290 case 0:
291 packet.SubCode.O1 = code;
292 break;
293 case 1:
294 packet.SubCode.O2 = code;
295 break;
296 case 2:
297 packet.SubCode.O3 = code;
298 break;
299 case 3:
300 packet.SubCode.O4 = code;
301 break;
302 }
303 pcount++;
304 }
305
306 /*
307 ** A packet block is ready for output into the destination buffer.
308 */
309 *dptr++ = packet.Char.C1;
310 dlen--;
311 total++;
312 if (dlen > 0 && pcount > 2) {
313 *dptr++ = packet.Char.C2;
314 dlen--;
315 total++;
316 }
317 if (dlen > 0 && pcount > 3) {
318 *dptr++ = packet.Char.C3;
319 dlen--;
320 total++;
321 }
322 }
323
324 /*
325 ** Return with the total number of characters decoded into the
326 ** output buffer.
327 */
328 return(total);
329}
330
331
332/*
333Base64 Content-Transfer-Encoding
334
335The Base64 Content-Transfer-Encoding is designed to represent arbitrary
336sequences of octets in a form that need not be humanly readable. The encoding
337and decoding algorithms are simple, but the encoded data are consistently
338only about 33 percent larger than the unencoded data. This encoding is
339virtually identical to the one used in Privacy Enhanced Mail (PEM)
340applications, as defined in RFC 1421. The base64 encoding is adapted from
341RFC 1421, with one change: base64 eliminates the "*" mechanism for embedded
342clear text.
343
344A 65-character subset of US-ASCII is used, enabling 6 bits to be represented
345per printable character. (The extra 65th character, "=", is used to signify a
346special processing function.)
347
348NOTE:
349 This subset has the important property that it is represented identically
350 in all versions of ISO 646, including US ASCII, and all characters in the
351 subset are also represented identically in all versions of EBCDIC. Other
352 popular encodings, such as the encoding used by the uuencode utility and
353 the base85 encoding specified as part of Level 2 PostScript, do not share
354 these properties, and thus do not fulfill the portability requirements a
355 binary transport encoding for mail must meet.
356
357The encoding process represents 24-bit groups of input bits as output strings
358of 4 encoded characters. Proceeding from left to right, a 24-bit input group is
359formed by concatenating 3 8-bit input groups. These 24 bits are then treated as
3604 concatenated 6-bit groups, each of which is translated into a single digit in
361the base64 alphabet. When encoding a bit stream via the base64 encoding, the
362bit stream must be presumed to be ordered with the most-significant-bit first.
363That is, the first bit in the stream will be the high-order bit in the first
364byte, and the eighth bit will be the low-order bit in the first byte, and so on.
365
366Each 6-bit group is used as an index into an array of 64 printable characters.
367The character referenced by the index is placed in the output string. These
368characters, identified in Table 1, below, are selected so as to be universally
369representable, and the set excludes characters with particular significance to
370SMTP (e.g., ".", CR, LF) and to the encapsulation boundaries defined in this
371document (e.g., "-").
372
373Table 1: The Base64 Alphabet
374
375 Value Encoding Value Encoding Value Encoding Value Encoding
376 0 A 17 R 34 i 51 z
377 1 B 18 S 35 j 52 0
378 2 C 19 T 36 k 53 1
379 3 D 20 U 37 l 54 2
380 4 E 21 V 38 m 55 3
381 5 F 22 W 39 n 56 4
382 6 G 23 X 40 o 57 5
383 7 H 24 Y 41 p 58 6
384 8 I 25 Z 42 q 59 7
385 9 J 26 a 43 r 60 8
386 10 K 27 b 44 s 61 9
387 11 L 28 c 45 t 62 +
388 12 M 29 d 46 u 63 /
389 13 N 30 e 47 v
390 14 O 31 f 48 w (pad) =
391 15 P 32 g 49 x
392 16 Q 33 h 50 y
393
394The output stream (encoded bytes) must be represented in lines of no more than
39576 characters each. All line breaks or other characters not found in Table 1
396must be ignored by decoding software. In base64 data, characters other than
397those in Table 1, line breaks, and other white space probably indicate a
398transmission error, about which a warning message or even a message rejection
399might be appropriate under some circumstances.
400
401Special processing is performed if fewer than 24 bits are available at the end
402of the data being encoded. A full encoding quantum is always completed at the
403end of a body. When fewer than 24 input bits are available in an input group,
404zero bits are added (on the right) to form an integral number of 6-bit groups.
405Padding at the end of the data is performed using the '=' character. Since all
406base64 input is an integral number of octets, only the following cases can
407arise: (1) the final quantum of encoding input is an integral multiple of 24
408bits; here, the final unit of encoded output will be an integral multiple of 4
409characters with no "=" padding, (2) the final quantum of encoding input is
410exactly 8 bits; here, the final unit of encoded output will be two characters
411followed by two "=" padding characters, or (3) the final quantum of encoding
412input is exactly 16 bits; here, the final unit of encoded output will be three
413characters followed by one "=" padding character.
414
415Because it is used only for padding at the end of the data, the occurrence of
416any '=' characters may be taken as evidence that the end of the data has been
417reached (without truncation in transit). No such assurance is possible,
418however, when the number of octets transmitted was a multiple of three.
419
420Any characters outside of the base64 alphabet are to be ignored in
421base64-encoded data. The same applies to any illegal sequence of characters in
422the base64 encoding, such as "====="
423
424Care must be taken to use the proper octets for line breaks if base64 encoding
425is applied directly to text material that has not been converted to canonical
426form. In particular, text line breaks must be converted into CRLF sequences
427prior to base64 encoding. The important thing to note is that this may be done
428directly by the encoder rather than in a prior canonicalization step in some
429implementations.
430
431NOTE:
432 There is no need to worry about quoting apparent encapsulation boundaries
433 within base64-encoded parts of multipart entities because no hyphen
434 characters are used in the base64 encoding.
435
436*/
#define NULL
Definition BaseType.h:92
char Char
Signed character (ASCII)
Definition BaseType.h:131
#define END
Definition base64.cpp:61
int Base64_Encode(void const *source, int slen, void *dest, int dlen)
Definition base64.cpp:142
int Base64_Decode(void const *source, int slen, void *dest, int dlen)
Definition base64.cpp:243
int const PacketChars
Definition base64.cpp:81
#define BAD
Definition base64.cpp:60
unsigned char C3
Definition base64.cpp:95
struct PacketType::@350006031310012046365372106367151200167372266267 Char
unsigned O4
Definition base64.cpp:108
unsigned O3
Definition base64.cpp:109
unsigned char C1
Definition base64.cpp:97
unsigned O1
Definition base64.cpp:111
unsigned char C2
Definition base64.cpp:96
unsigned int Raw
Definition base64.cpp:115
unsigned char pad
Definition base64.cpp:99
struct PacketType::@171075251260353216307371332356367037344113010177 SubCode
unsigned O2
Definition base64.cpp:110