BASE64.CPP 19 KB

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