CnC_Remastered_Collection

Command and Conquer: Red Alert
Log | Files | Refs | README | LICENSE

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 */