1: using System.Text;
2:
3: namespace Base64
4: {
5: public class Base64
6: {
7: #region mask variables
8: private const int clOneMask = 16515072; //000000 111111 111111 111111
9: private const int clTwoMask = 258048; //111111 000000 111111 111111
10: private const int clThreeMask = 4032; //111111 111111 000000 111111
11: private const int clFourMask = 63; //111111 111111 111111 000000
12:
13: private const int clHighMask = 16711680; //11111111 00000000 00000000
14: private const int clMidMask = 65280; //00000000 11111111 00000000
15: private const int clLowMask = 255; //00000000 00000000 11111111
16: #endregion
17:
18: #region power of 2 variables
19: private const int cl2Exp18 = 262144; //2 to the 18th power
20: private const int cl2Exp12 = 4096; //2 to the 12th
21: private const int cl2Exp6 = 64; //2 to the 6th
22: private const int cl2Exp8 = 256; //2 to the 8th
23: private const int cl2Exp16 = 65536; //2 to the 16th
24: #endregion
25:
26: #region array variables
27: private byte[] cbTransTo = new byte[64];
28: private byte[] cbTransFrom = new byte[256];
29: private long[] clPowers8 = new long[256];
30: private long[] clPowers16 = new long[256];
31: private long[] clPowers6 = new long[64];
32: private long[] clPowers12 = new long[64];
33: private long[] clPowers18 = new long[64];
34: #endregion
35:
36: #region .ctor
37: public Base64()
38: {
39: long lTemp = 0;
40:
41: for (lTemp = 0; lTemp <= 63; lTemp++) //Fill the translation table.
42: {
43: if (lTemp >= 0 && lTemp <= 25)
44: {
45: cbTransTo[lTemp] = (byte)(65 + lTemp); //A - Z
46: }
47: else if (lTemp >= 26 && lTemp <= 51)
48: {
49: cbTransTo[lTemp] = (byte)(71 + lTemp); //a - z
50: }
51: else if (lTemp >= 52 && lTemp <= 61)
52: {
53: cbTransTo[lTemp] = (byte)(lTemp - 4); //1 - 0
54: }
55: else if (lTemp == 62)
56: {
57: cbTransTo[lTemp] = 43; //Chr(43) = "+"
58: }
59: else if (lTemp == 63)
60: {
61: cbTransTo[lTemp] = 47; //Chr(47) = "/"
62: }
63: }
64:
65: for (lTemp = 0; lTemp <= 255; lTemp++) //Fill the lookup tables.
66: {
67: clPowers8[lTemp] = lTemp * cl2Exp8;
68: clPowers16[lTemp] = lTemp * cl2Exp16;
69: }
70:
71: for (lTemp = 0; lTemp <= 63; lTemp++)
72: {
73: clPowers6[lTemp] = lTemp * cl2Exp6;
74: clPowers12[lTemp] = lTemp * cl2Exp12;
75: clPowers18[lTemp] = lTemp * cl2Exp18;
76: }
77:
78: for (lTemp = 0; lTemp <= 255; lTemp++) //Fill the translation table.
79: {
80: if (lTemp >= 65 && lTemp <= 90)
81: {
82: cbTransFrom[lTemp] = (byte)(lTemp - 65); //A - Z
83: }
84: else if (lTemp >= 97 && lTemp <= 122)
85: {
86: cbTransFrom[lTemp] = (byte)(lTemp - 71); //a - z
87: }
88: else if (lTemp >= 48 && lTemp <= 57)
89: {
90: cbTransFrom[lTemp] = (byte)(lTemp + 4); //1 - 0
91: }
92: else if (lTemp == 43)
93: {
94: cbTransFrom[lTemp] = 62; //Chr(43) = "+"
95: }
96: else if (lTemp == 47)
97: {
98: cbTransFrom[lTemp] = 63; //Chr(47) = "/"
99: }
100: }
101: }
102: #endregion
103:
104: //String --> Base 64 Format String
105: public string Encode(string sString)
106: {
107: byte[] bTrans = new byte[64];
108: byte[] bOut, bIn;
109: int iPad = 0;
110: long lOutSize = 0;
111: long lChar = 0;
112: long lTrip = 0;
113: long lLen = 0;
114: long lTemp = 0;
115: long lPos = 0;
116:
117: iPad = sString.Length % 3; //Check if the length is divisible by 3 for 3 character
118: if (iPad != 0) //If not, figure out the end pad and resize the input.
119: {
120: iPad = 3 - iPad;
121: sString = sString.PadRight(iPad + sString.Length, '\0');
122: }
123:
124: bIn = Encoding.Default.GetBytes(sString); //Load the input string.
125: lLen = ((bIn.GetUpperBound(0) + 1) / 3) * 4; //Length of resulting string.
126: lOutSize = lLen - 1; //Calculate the size of the output buffer.
127: bOut = new byte[lOutSize + 1]; //Make the output buffer.
128:
129: lLen = 0; //Reusing this one, so reset it.
130:
131: for (lChar = bIn.GetLowerBound(0); lChar <= bIn.GetUpperBound(0); lChar += 3)
132: {
133: lTrip = clPowers16[bIn[lChar]]
134: + clPowers8[bIn[lChar + 1]]
135: + bIn[lChar + 2]; //Combine the 3 bytes
136: lTemp = lTrip & clOneMask; //Mask for the first 6 bits
137: bOut[lPos] = cbTransTo[lTemp / cl2Exp18]; //Shift it down to the low 6 bits and get the value
138: lTemp = lTrip & clTwoMask; //Mask for the second set.
139: bOut[lPos + 1] = cbTransTo[lTemp / cl2Exp12]; //Shift it down and translate.
140: lTemp = lTrip & clThreeMask; //Mask for the third set.
141: bOut[lPos + 2] = cbTransTo[lTemp / cl2Exp6]; //Shift it down and translate.
142: bOut[lPos + 3] = cbTransTo[lTrip & clFourMask]; //Mask for the low set.
143:
144: lLen = lLen + 4;
145: lPos = lPos + 4;
146: }
147:
148: if (iPad == 1) //Add the padding chars if any.
149: {
150: bOut[lOutSize] = 61; //Chr(61) = "="
151: }
152: else if (iPad == 2)
153: {
154: bOut[lOutSize] = 61;
155: bOut[lOutSize - 1] = 61;
156: }
157:
158: return Encoding.Default.GetString(bOut); // Encoding.Unicode.GetString(bOut);
159: }
160:
161: //Base64 Format String --> String
162: public string Decode(string sString)
163: {
164: byte[] bOut = null;
165: byte[] bIn = null;
166: int iPad = 0;
167: long lQuad = 0;
168: long lChar = 0;
169: long lPos = 0;
170: long lTemp = 0;
171: string sOut = null;
172:
173: lTemp = sString.Length % 4; //Test for valid input.
174: if (lTemp != 0)
175: {
176: return "Error: It's not base64 format string";
177: }
178:
179: if ((sString.LastIndexOf("==") + 1) != 0) //InStrRev is faster when you know it's at the end.
180: {
181: iPad = 2; //Note: These translate to 0, so you can leave them...
182: }
183: else if ((sString.LastIndexOf("=") + 1) != 0) //in the string and just resize the output.
184: {
185: iPad = 1;
186: }
187:
188: bIn = Encoding.Default.GetBytes(sString); //Load the input byte array.
189: bOut = new byte[(((bIn.GetUpperBound(0) + 1) / 4) * 3)]; //Prepare the output buffer.
190:
191: for (lChar = 0; lChar <= bIn.GetUpperBound(0); lChar += 4)
192: {
193: lQuad = clPowers18[cbTransFrom[bIn[lChar]]] + clPowers12[cbTransFrom[bIn[lChar + 1]]] + clPowers6[cbTransFrom[bIn[lChar + 2]]] + cbTransFrom[bIn[lChar + 3]]; //Rebuild the bits.
194: lTemp = lQuad & clHighMask; //Mask for the first byte
195: bOut[lPos] = (byte)(lTemp / cl2Exp16); //Shift it down
196: lTemp = lQuad & clMidMask; //Mask for the second byte
197: bOut[lPos + 1] = (byte)(lTemp / cl2Exp8); //Shift it down
198: bOut[lPos + 2] = (byte)(lQuad & clLowMask); //Mask for the third byte
199: lPos = lPos + 3;
200: }
201:
202: sOut = Encoding.Default.GetString(bOut); //Encoding.Unicode.GetString(bOut); //Convert back to a string.
203:
204: if (iPad != 0) //Chop off any extra bytes.
205: {
206: sOut = sOut.Substring(0, sOut.Length - iPad);
207: }
208:
209: return sOut;
210: }
211: }
212: }