Base64Encoder.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.IO;
  5. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Encoders
  6. {
  7. public class Base64Encoder
  8. : IEncoder
  9. {
  10. protected readonly byte[] encodingTable =
  11. {
  12. (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
  13. (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
  14. (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
  15. (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
  16. (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
  17. (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
  18. (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
  19. (byte)'v',
  20. (byte)'w', (byte)'x', (byte)'y', (byte)'z',
  21. (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6',
  22. (byte)'7', (byte)'8', (byte)'9',
  23. (byte)'+', (byte)'/'
  24. };
  25. protected byte padding = (byte)'=';
  26. /*
  27. * set up the decoding table.
  28. */
  29. protected readonly byte[] decodingTable = new byte[128];
  30. protected void InitialiseDecodingTable()
  31. {
  32. Arrays.Fill(decodingTable, (byte)0xff);
  33. for (int i = 0; i < encodingTable.Length; i++)
  34. {
  35. decodingTable[encodingTable[i]] = (byte)i;
  36. }
  37. }
  38. public Base64Encoder()
  39. {
  40. InitialiseDecodingTable();
  41. }
  42. public int Encode(byte[] inBuf, int inOff, int inLen, byte[] outBuf, int outOff)
  43. {
  44. int inPos = inOff;
  45. int inEnd = inOff + inLen - 2;
  46. int outPos = outOff;
  47. while (inPos < inEnd)
  48. {
  49. uint a1 = inBuf[inPos++];
  50. uint a2 = inBuf[inPos++];
  51. uint a3 = inBuf[inPos++];
  52. outBuf[outPos++] = encodingTable[(a1 >> 2) & 0x3F];
  53. outBuf[outPos++] = encodingTable[((a1 << 4) | (a2 >> 4)) & 0x3F];
  54. outBuf[outPos++] = encodingTable[((a2 << 2) | (a3 >> 6)) & 0x3F];
  55. outBuf[outPos++] = encodingTable[a3 & 0x3F];
  56. }
  57. switch (inLen - (inPos - inOff))
  58. {
  59. case 1:
  60. {
  61. uint a1 = inBuf[inPos++];
  62. outBuf[outPos++] = encodingTable[(a1 >> 2) & 0x3F];
  63. outBuf[outPos++] = encodingTable[(a1 << 4) & 0x3F];
  64. outBuf[outPos++] = padding;
  65. outBuf[outPos++] = padding;
  66. break;
  67. }
  68. case 2:
  69. {
  70. uint a1 = inBuf[inPos++];
  71. uint a2 = inBuf[inPos++];
  72. outBuf[outPos++] = encodingTable[(a1 >> 2) & 0x3F];
  73. outBuf[outPos++] = encodingTable[((a1 << 4) | (a2 >> 4)) & 0x3F];
  74. outBuf[outPos++] = encodingTable[(a2 << 2) & 0x3F];
  75. outBuf[outPos++] = padding;
  76. break;
  77. }
  78. }
  79. return outPos - outOff;
  80. }
  81. /**
  82. * encode the input data producing a base 64 output stream.
  83. *
  84. * @return the number of bytes produced.
  85. */
  86. public int Encode(byte[] buf, int off, int len, Stream outStream)
  87. {
  88. if (len < 0)
  89. return 0;
  90. byte[] tmp = new byte[72];
  91. int remaining = len;
  92. while (remaining > 0)
  93. {
  94. int inLen = System.Math.Min(54, remaining);
  95. int outLen = Encode(buf, off, inLen, tmp, 0);
  96. outStream.Write(tmp, 0, outLen);
  97. off += inLen;
  98. remaining -= inLen;
  99. }
  100. return (len + 2) / 3 * 4;
  101. }
  102. private bool Ignore(char c)
  103. {
  104. return c == '\n' || c =='\r' || c == '\t' || c == ' ';
  105. }
  106. /**
  107. * decode the base 64 encoded byte data writing it to the given output stream,
  108. * whitespace characters will be ignored.
  109. *
  110. * @return the number of bytes produced.
  111. */
  112. public int Decode(byte[] data, int off, int length, Stream outStream)
  113. {
  114. byte b1, b2, b3, b4;
  115. byte[] outBuffer = new byte[54]; // S/MIME standard
  116. int bufOff = 0;
  117. int outLen = 0;
  118. int end = off + length;
  119. while (end > off)
  120. {
  121. if (!Ignore((char)data[end - 1]))
  122. break;
  123. end--;
  124. }
  125. int i = off;
  126. int finish = end - 4;
  127. i = NextI(data, i, finish);
  128. while (i < finish)
  129. {
  130. b1 = decodingTable[data[i++]];
  131. i = NextI(data, i, finish);
  132. b2 = decodingTable[data[i++]];
  133. i = NextI(data, i, finish);
  134. b3 = decodingTable[data[i++]];
  135. i = NextI(data, i, finish);
  136. b4 = decodingTable[data[i++]];
  137. if ((b1 | b2 | b3 | b4) >= 0x80)
  138. throw new IOException("invalid characters encountered in base64 data");
  139. outBuffer[bufOff++] = (byte)((b1 << 2) | (b2 >> 4));
  140. outBuffer[bufOff++] = (byte)((b2 << 4) | (b3 >> 2));
  141. outBuffer[bufOff++] = (byte)((b3 << 6) | b4);
  142. if (bufOff == outBuffer.Length)
  143. {
  144. outStream.Write(outBuffer, 0, bufOff);
  145. bufOff = 0;
  146. }
  147. outLen += 3;
  148. i = NextI(data, i, finish);
  149. }
  150. if (bufOff > 0)
  151. {
  152. outStream.Write(outBuffer, 0, bufOff);
  153. }
  154. int e0 = NextI(data, i, end);
  155. int e1 = NextI(data, e0 + 1, end);
  156. int e2 = NextI(data, e1 + 1, end);
  157. int e3 = NextI(data, e2 + 1, end);
  158. outLen += DecodeLastBlock(outStream, (char)data[e0], (char)data[e1], (char)data[e2], (char)data[e3]);
  159. return outLen;
  160. }
  161. private int NextI(
  162. byte[] data,
  163. int i,
  164. int finish)
  165. {
  166. while ((i < finish) && Ignore((char)data[i]))
  167. {
  168. i++;
  169. }
  170. return i;
  171. }
  172. /**
  173. * decode the base 64 encoded string data writing it to the given output stream,
  174. * whitespace characters will be ignored.
  175. *
  176. * @return the number of bytes produced.
  177. */
  178. public int DecodeString(string data, Stream outStream)
  179. {
  180. // Platform Implementation
  181. // byte[] bytes = Convert.FromBase64String(data);
  182. // outStream.Write(bytes, 0, bytes.Length);
  183. // return bytes.Length;
  184. byte b1, b2, b3, b4;
  185. int length = 0;
  186. int end = data.Length;
  187. while (end > 0)
  188. {
  189. if (!Ignore(data[end - 1]))
  190. break;
  191. end--;
  192. }
  193. int i = 0;
  194. int finish = end - 4;
  195. i = NextI(data, i, finish);
  196. while (i < finish)
  197. {
  198. b1 = decodingTable[data[i++]];
  199. i = NextI(data, i, finish);
  200. b2 = decodingTable[data[i++]];
  201. i = NextI(data, i, finish);
  202. b3 = decodingTable[data[i++]];
  203. i = NextI(data, i, finish);
  204. b4 = decodingTable[data[i++]];
  205. if ((b1 | b2 | b3 | b4) >= 0x80)
  206. throw new IOException("invalid characters encountered in base64 data");
  207. outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
  208. outStream.WriteByte((byte)((b2 << 4) | (b3 >> 2)));
  209. outStream.WriteByte((byte)((b3 << 6) | b4));
  210. length += 3;
  211. i = NextI(data, i, finish);
  212. }
  213. length += DecodeLastBlock(outStream, data[end - 4], data[end - 3], data[end - 2], data[end - 1]);
  214. return length;
  215. }
  216. private int DecodeLastBlock(
  217. Stream outStream,
  218. char c1,
  219. char c2,
  220. char c3,
  221. char c4)
  222. {
  223. if (c3 == padding)
  224. {
  225. if (c4 != padding)
  226. throw new IOException("invalid characters encountered at end of base64 data");
  227. byte b1 = decodingTable[c1];
  228. byte b2 = decodingTable[c2];
  229. if ((b1 | b2) >= 0x80)
  230. throw new IOException("invalid characters encountered at end of base64 data");
  231. outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
  232. return 1;
  233. }
  234. if (c4 == padding)
  235. {
  236. byte b1 = decodingTable[c1];
  237. byte b2 = decodingTable[c2];
  238. byte b3 = decodingTable[c3];
  239. if ((b1 | b2 | b3) >= 0x80)
  240. throw new IOException("invalid characters encountered at end of base64 data");
  241. outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
  242. outStream.WriteByte((byte)((b2 << 4) | (b3 >> 2)));
  243. return 2;
  244. }
  245. {
  246. byte b1 = decodingTable[c1];
  247. byte b2 = decodingTable[c2];
  248. byte b3 = decodingTable[c3];
  249. byte b4 = decodingTable[c4];
  250. if ((b1 | b2 | b3 | b4) >= 0x80)
  251. throw new IOException("invalid characters encountered at end of base64 data");
  252. outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
  253. outStream.WriteByte((byte)((b2 << 4) | (b3 >> 2)));
  254. outStream.WriteByte((byte)((b3 << 6) | b4));
  255. return 3;
  256. }
  257. }
  258. private int NextI(string data, int i, int finish)
  259. {
  260. while ((i < finish) && Ignore(data[i]))
  261. {
  262. i++;
  263. }
  264. return i;
  265. }
  266. }
  267. }
  268. #pragma warning restore
  269. #endif