minor whitespace change
[rocksndiamonds.git] / src / libgame / base64.c
1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2021 by Artsoft Entertainment
5 //                  Holger Schemel
6 //                  info@artsoft.org
7 //                  https://www.artsoft.org/
8 // ----------------------------------------------------------------------------
9 // base64.c
10 // ============================================================================
11
12 /*
13
14   https://github.com/superwills/NibbleAndAHalf
15   base64.h -- Fast base64 encoding and decoding.
16   version 1.0.0, April 17, 2013 143a
17
18   Copyright (C) 2013 William Sherif
19
20   This software is provided 'as-is', without any express or implied
21   warranty.  In no event will the authors be held liable for any damages
22   arising from the use of this software.
23
24   Permission is granted to anyone to use this software for any purpose,
25   including commercial applications, and to alter it and redistribute it
26   freely, subject to the following restrictions:
27
28   1. The origin of this software must not be misrepresented; you must not
29      claim that you wrote the original software. If you use this software
30      in a product, an acknowledgment in the product documentation would be
31      appreciated but is not required.
32   2. Altered source versions must be plainly marked as such, and must not be
33      misrepresented as being the original software.
34   3. This notice may not be removed or altered from any source distribution.
35
36   William Sherif
37   will.sherif@gmail.com
38
39   YWxsIHlvdXIgYmFzZSBhcmUgYmVsb25nIHRvIHVz
40
41 */
42
43 #include <stdio.h>
44 #include <stdlib.h>
45
46 #include "base64.h"
47
48
49 const static char* b64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ;
50
51 // maps A=>0,B=>1..
52 const static unsigned char unb64[]={
53   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //10
54   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //20
55   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //30
56   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //40
57   0,   0,   0,  62,   0,   0,   0,  63,  52,  53, //50
58  54,  55,  56,  57,  58,  59,  60,  61,   0,   0, //60
59   0,   0,   0,   0,   0,   0,   1,   2,   3,   4, //70
60   5,   6,   7,   8,   9,  10,  11,  12,  13,  14, //80
61  15,  16,  17,  18,  19,  20,  21,  22,  23,  24, //90
62  25,   0,   0,   0,   0,   0,   0,  26,  27,  28, //100
63  29,  30,  31,  32,  33,  34,  35,  36,  37,  38, //110
64  39,  40,  41,  42,  43,  44,  45,  46,  47,  48, //120
65  49,  50,  51,   0,   0,   0,   0,   0,   0,   0, //130
66   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //140
67   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //150
68   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //160
69   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //170
70   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //180
71   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //190
72   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //200
73   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //210
74   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //220
75   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //230
76   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //240
77   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //250
78   0,   0,   0,   0,   0,   0,
79 }; // This array has 256 elements
80
81 // Converts binary data of length=len to base64 characters.
82 // Length of the resultant string is stored in flen
83 // (you must pass pointer flen).
84 char* base64( const void* binaryData, int len, int *flen )
85 {
86   const unsigned char* bin = (const unsigned char*) binaryData ;
87   char* res ;
88
89   int rc = 0 ; // result counter
90   int byteNo ; // I need this after the loop
91
92   int modulusLen = len % 3 ;
93   int pad = ((modulusLen&1)<<1) + ((modulusLen&2)>>1) ; // 2 gives 1 and 1 gives 2, but 0 gives 0.
94
95   *flen = 4*(len + pad)/3 ;
96   res = (char*) malloc( *flen + 1 ) ; // and one for the null
97   if( !res )
98   {
99     puts( "ERROR: base64 could not allocate enough memory." ) ;
100     puts( "I must stop because I could not get enough" ) ;
101     return 0;
102   }
103
104   for( byteNo = 0 ; byteNo <= len-3 ; byteNo+=3 )
105   {
106     unsigned char BYTE0=bin[byteNo];
107     unsigned char BYTE1=bin[byteNo+1];
108     unsigned char BYTE2=bin[byteNo+2];
109     res[rc++]  = b64[ BYTE0 >> 2 ] ;
110     res[rc++]  = b64[ ((0x3&BYTE0)<<4) + (BYTE1 >> 4) ] ;
111     res[rc++]  = b64[ ((0x0f&BYTE1)<<2) + (BYTE2>>6) ] ;
112     res[rc++]  = b64[ 0x3f&BYTE2 ] ;
113   }
114
115   if( pad==2 )
116   {
117     res[rc++] = b64[ bin[byteNo] >> 2 ] ;
118     res[rc++] = b64[ (0x3&bin[byteNo])<<4 ] ;
119     res[rc++] = '=';
120     res[rc++] = '=';
121   }
122   else if( pad==1 )
123   {
124     res[rc++]  = b64[ bin[byteNo] >> 2 ] ;
125     res[rc++]  = b64[ ((0x3&bin[byteNo])<<4)   +   (bin[byteNo+1] >> 4) ] ;
126     res[rc++]  = b64[ (0x0f&bin[byteNo+1])<<2 ] ;
127     res[rc++] = '=';
128   }
129
130   res[rc]=0; // NULL TERMINATOR! ;)
131   return res ;
132 }
133
134 unsigned char* unbase64( const char* ascii, int len, int *flen )
135 {
136   const unsigned char *safeAsciiPtr = (const unsigned char*)ascii ;
137   unsigned char *bin ;
138   int cb=0;
139   int charNo;
140   int pad = 0 ;
141
142   if( len < 2 ) { // 2 accesses below would be OOB.
143     // catch empty string, return NULL as result.
144     puts( "ERROR: You passed an invalid base64 string (too short). You get NULL back." ) ;
145     *flen=0;
146     return 0 ;
147   }
148   if( safeAsciiPtr[ len-1 ]=='=' )  ++pad ;
149   if( safeAsciiPtr[ len-2 ]=='=' )  ++pad ;
150
151   *flen = 3*len/4 - pad ;
152   bin = (unsigned char*)malloc( *flen ) ;
153   if( !bin )
154   {
155     puts( "ERROR: unbase64 could not allocate enough memory." ) ;
156     puts( "I must stop because I could not get enough" ) ;
157     return 0;
158   }
159
160   for( charNo=0; charNo <= len - 4 - pad ; charNo+=4 )
161   {
162     int A=unb64[safeAsciiPtr[charNo]];
163     int B=unb64[safeAsciiPtr[charNo+1]];
164     int C=unb64[safeAsciiPtr[charNo+2]];
165     int D=unb64[safeAsciiPtr[charNo+3]];
166
167     bin[cb++] = (A<<2) | (B>>4) ;
168     bin[cb++] = (B<<4) | (C>>2) ;
169     bin[cb++] = (C<<6) | (D) ;
170   }
171
172   if( pad==1 )
173   {
174     int A=unb64[safeAsciiPtr[charNo]];
175     int B=unb64[safeAsciiPtr[charNo+1]];
176     int C=unb64[safeAsciiPtr[charNo+2]];
177
178     bin[cb++] = (A<<2) | (B>>4) ;
179     bin[cb++] = (B<<4) | (C>>2) ;
180   }
181   else if( pad==2 )
182   {
183     int A=unb64[safeAsciiPtr[charNo]];
184     int B=unb64[safeAsciiPtr[charNo+1]];
185
186     bin[cb++] = (A<<2) | (B>>4) ;
187   }
188
189   return bin ;
190 }