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