base64.cpp 18 KB

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