PageRenderTime 46ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/source/library/com/restfb/util/EncodingUtils.java

https://github.com/revetkn/restfb
Java | 717 lines | 326 code | 91 blank | 300 comment | 129 complexity | 29eeeaed0bec9d093477497900337404 MD5 | raw file
Possible License(s): JSON
  1. /*
  2. * Copyright (c) 2010-2014 Mark Allen.
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. * THE SOFTWARE.
  21. */
  22. package com.restfb.util;
  23. import java.io.UnsupportedEncodingException;
  24. import java.security.InvalidKeyException;
  25. import java.security.NoSuchAlgorithmException;
  26. import java.util.Arrays;
  27. import javax.crypto.Mac;
  28. import javax.crypto.spec.SecretKeySpec;
  29. /**
  30. * A collection of data-encoding utility methods.
  31. *
  32. * @author Josef Gierbl
  33. * @author Mikael Grev
  34. * @author <a href="http://restfb.com">Mark Allen</a>
  35. * @since 1.6.13
  36. */
  37. public final class EncodingUtils {
  38. /**
  39. * Prevents instantiation.
  40. */
  41. private EncodingUtils() {}
  42. /**
  43. * Decodes a base64-encoded string, padding out if necessary.
  44. *
  45. * @param base64
  46. * The base64-encoded string to decode.
  47. * @return A decoded version of {@code base64}.
  48. * @throws NullPointerException
  49. * If {@code base64} is {@code null}.
  50. */
  51. public static byte[] decodeBase64(String base64) {
  52. if (base64 == null)
  53. throw new NullPointerException("Parameter 'base64' cannot be null.");
  54. base64 = padBase64(base64);
  55. return Base64.decode(base64);
  56. }
  57. private static String padBase64(String base64) {
  58. String padding = "";
  59. int remainder = base64.length() % 4;
  60. if (remainder == 1)
  61. padding = "===";
  62. else if (remainder == 2)
  63. padding = "==";
  64. else if (remainder == 3)
  65. padding = "=";
  66. return base64 + padding;
  67. }
  68. /**
  69. * Encodes a hex {@code byte[]} from given {@code byte[]}.
  70. *
  71. * This function is equivalent to Apache commons-codec binary {@code new Hex().encode(byte[])}
  72. *
  73. * @param data
  74. * The data to encode as hex.
  75. * @return Hex-encoded {@code byte[]}
  76. * @throws NullPointerException
  77. * If {@code data} is {@code null}.
  78. */
  79. public static byte[] encodeHex(final byte[] data) {
  80. if (data == null)
  81. throw new NullPointerException("Parameter 'data' cannot be null.");
  82. final char[] toDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
  83. final int l = data.length;
  84. final char[] out = new char[l << 1];
  85. for (int i = 0, j = 0; i < l; i++) {
  86. out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
  87. out[j++] = toDigits[0x0F & data[i]];
  88. }
  89. return new String(out).getBytes();
  90. }
  91. /**
  92. * Generates an appsecret_proof for facebook.
  93. *
  94. * See https://developers.facebook.com/docs/graph-api/securing-requests for more info
  95. *
  96. * @param appSecret
  97. * The facebook application secret
  98. * @param accessToken
  99. * The facebook access token
  100. * @return A Hex encoded SHA256 Hash as a String
  101. * @throws NoSuchAlgorithmException
  102. * @throws InvalidKeyException
  103. * @throws UnsupportedEncodingException
  104. */
  105. public static String encodeAppSecretProof(String appSecret, String accessToken) throws NoSuchAlgorithmException,
  106. InvalidKeyException, UnsupportedEncodingException {
  107. byte[] key = appSecret.getBytes();
  108. SecretKeySpec signingKey = new SecretKeySpec(key, "HmacSHA256");
  109. Mac mac = Mac.getInstance("HmacSHA256");
  110. mac.init(signingKey);
  111. byte[] raw = mac.doFinal(accessToken.getBytes());
  112. byte[] hex = encodeHex(raw);
  113. String out = new String(hex, "UTF-8");
  114. return out;
  115. }
  116. /**
  117. * A very fast and memory efficient class to encode and decode to and from BASE64 in full accordance with RFC 2045.<br>
  118. * <br>
  119. * On Windows XP sp1 with 1.4.2_04 and later ;), this encoder and decoder is about 10 times faster on small arrays (10
  120. * - 1000 bytes) and 2-3 times as fast on larger arrays (10000 - 1000000 bytes) compared to
  121. * <code>sun.misc.Encoder()/Decoder()</code>.<br>
  122. * <br>
  123. *
  124. * On byte arrays the encoder is about 20% faster than Jakarta Commons Base64 Codec for encode and about 50% faster
  125. * for decoding large arrays. This implementation is about twice as fast on very small arrays (&lt 30 bytes). If
  126. * source/destination is a <code>String</code> this version is about three times as fast due to the fact that the
  127. * Commons Codec result has to be recoded to a <code>String</code> from <code>byte[]</code>, which is very expensive.<br>
  128. * <br>
  129. *
  130. * This encode/decode algorithm doesn't create any temporary arrays as many other codecs do, it only allocates the
  131. * resulting array. This produces less garbage and it is possible to handle arrays twice as large as algorithms that
  132. * create a temporary array. (E.g. Jakarta Commons Codec). It is unknown whether Sun's
  133. * <code>sun.misc.Encoder()/Decoder()</code> produce temporary arrays but since performance is quite low it probably
  134. * does.<br>
  135. * <br>
  136. *
  137. * The encoder produces the same output as the Sun one except that the Sun's encoder appends a trailing line separator
  138. * if the last character isn't a pad. Unclear why but it only adds to the length and is probably a side effect. Both
  139. * are in conformance with RFC 2045 though.<br>
  140. * Commons codec seem to always att a trailing line separator.<br>
  141. * <br>
  142. *
  143. * <b>Note!</b> The encode/decode method pairs (types) come in three versions with the <b>exact</b> same algorithm and
  144. * thus a lot of code redundancy. This is to not create any temporary arrays for transcoding to/from different format
  145. * types. The methods not used can simply be commented out.<br>
  146. * <br>
  147. *
  148. * There is also a "fast" version of all decode methods that works the same way as the normal ones, but har a few
  149. * demands on the decoded input. Normally though, these fast verions should be used if the source if the input is
  150. * known and it hasn't bee tampered with.<br>
  151. * <br>
  152. *
  153. * If you find the code useful or you find a bug, please send me a note at base64 @ miginfocom . com.
  154. *
  155. * Licence (BSD): ==============
  156. *
  157. * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (base64 @ miginfocom . com) All rights reserved.
  158. *
  159. * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
  160. * following conditions are met: Redistributions of source code must retain the above copyright notice, this list of
  161. * conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice,
  162. * this list of conditions and the following disclaimer in the documentation and/or other materials provided with the
  163. * distribution. Neither the name of the MiG InfoCom AB nor the names of its contributors may be used to endorse or
  164. * promote products derived from this software without specific prior written permission.
  165. *
  166. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  167. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  168. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  169. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  170. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  171. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  172. * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  173. *
  174. * @version 2.2
  175. * @author Mikael Grev Date: 2004-aug-02 Time: 11:31:11
  176. */
  177. @SuppressWarnings("unused")
  178. private static class Base64 {
  179. private static final char[] CA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
  180. private static final int[] IA = new int[256];
  181. static {
  182. Arrays.fill(IA, -1);
  183. for (int i = 0, iS = CA.length; i < iS; i++)
  184. IA[CA[i]] = i;
  185. IA['='] = 0;
  186. }
  187. // ****************************************************************************************
  188. // * char[] version
  189. // ****************************************************************************************
  190. /**
  191. * Encodes a raw byte array into a BASE64 <code>char[]</code> representation i accordance with RFC 2045.
  192. *
  193. * @param sArr
  194. * The bytes to convert. If <code>null</code> or length 0 an empty array will be returned.
  195. * @param lineSep
  196. * Optional "\r\n" after 76 characters, unless end of file.<br>
  197. * No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a little
  198. * faster.
  199. * @return A BASE64 encoded array. Never <code>null</code>.
  200. */
  201. public final static char[] encodeToChar(byte[] sArr, boolean lineSep) {
  202. // Check special case
  203. int sLen = sArr != null ? sArr.length : 0;
  204. if (sLen == 0)
  205. return new char[0];
  206. int eLen = (sLen / 3) * 3; // Length of even 24-bits.
  207. int cCnt = ((sLen - 1) / 3 + 1) << 2; // Returned character count
  208. int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of returned array
  209. char[] dArr = new char[dLen];
  210. // Encode even 24-bits
  211. for (int s = 0, d = 0, cc = 0; s < eLen;) {
  212. // Copy next three bytes into lower 24 bits of int, paying attension to sign.
  213. int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | (sArr[s++] & 0xff);
  214. // Encode the int into four chars
  215. dArr[d++] = CA[(i >>> 18) & 0x3f];
  216. dArr[d++] = CA[(i >>> 12) & 0x3f];
  217. dArr[d++] = CA[(i >>> 6) & 0x3f];
  218. dArr[d++] = CA[i & 0x3f];
  219. // Add optional line separator
  220. if (lineSep && ++cc == 19 && d < dLen - 2) {
  221. dArr[d++] = '\r';
  222. dArr[d++] = '\n';
  223. cc = 0;
  224. }
  225. }
  226. // Pad and encode last bits if source isn't even 24 bits.
  227. int left = sLen - eLen; // 0 - 2.
  228. if (left > 0) {
  229. // Prepare the int
  230. int i = ((sArr[eLen] & 0xff) << 10) | (left == 2 ? ((sArr[sLen - 1] & 0xff) << 2) : 0);
  231. // Set last four chars
  232. dArr[dLen - 4] = CA[i >> 12];
  233. dArr[dLen - 3] = CA[(i >>> 6) & 0x3f];
  234. dArr[dLen - 2] = left == 2 ? CA[i & 0x3f] : '=';
  235. dArr[dLen - 1] = '=';
  236. }
  237. return dArr;
  238. }
  239. /**
  240. * Decodes a BASE64 encoded char array. All illegal characters will be ignored and can handle both arrays with and
  241. * without line separators.
  242. *
  243. * @param sArr
  244. * The source array. <code>null</code> or length 0 will return an empty array.
  245. * @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters
  246. * (including '=') isn't divideable by 4. (I.e. definitely corrupted).
  247. */
  248. public final static byte[] decode(char[] sArr) {
  249. // Check special case
  250. int sLen = sArr != null ? sArr.length : 0;
  251. if (sLen == 0)
  252. return new byte[0];
  253. // Count illegal characters (including '\r', '\n') to know what size the returned array will be,
  254. // so we don't have to reallocate & copy it later.
  255. int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
  256. for (int i = 0; i < sLen; i++)
  257. // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out.
  258. if (IA[sArr[i]] < 0)
  259. sepCnt++;
  260. // Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
  261. if ((sLen - sepCnt) % 4 != 0)
  262. return null;
  263. int pad = 0;
  264. for (int i = sLen; i > 1 && IA[sArr[--i]] <= 0;)
  265. if (sArr[i] == '=')
  266. pad++;
  267. int len = ((sLen - sepCnt) * 6 >> 3) - pad;
  268. byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
  269. for (int s = 0, d = 0; d < len;) {
  270. // Assemble three bytes into an int from four "valid" characters.
  271. int i = 0;
  272. for (int j = 0; j < 4; j++) { // j only increased if a valid char was found.
  273. int c = IA[sArr[s++]];
  274. if (c >= 0)
  275. i |= c << (18 - j * 6);
  276. else
  277. j--;
  278. }
  279. // Add the bytes
  280. dArr[d++] = (byte) (i >> 16);
  281. if (d < len) {
  282. dArr[d++] = (byte) (i >> 8);
  283. if (d < len)
  284. dArr[d++] = (byte) i;
  285. }
  286. }
  287. return dArr;
  288. }
  289. /**
  290. * Decodes a BASE64 encoded char array that is known to be resonably well formatted. The method is about twice as
  291. * fast as {@link #decode(char[])}. The preconditions are:<br>
  292. * + The array must have a line length of 76 chars OR no line separators at all (one line).<br>
  293. * + Line separator must be "\r\n", as specified in RFC 2045 + The array must not contain illegal characters within
  294. * the encoded string<br>
  295. * + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br>
  296. *
  297. * @param sArr
  298. * The source array. Length 0 will return an empty array. <code>null</code> will throw an exception.
  299. * @return The decoded array of bytes. May be of length 0.
  300. */
  301. public final static byte[] decodeFast(char[] sArr) {
  302. // Check special case
  303. int sLen = sArr.length;
  304. if (sLen == 0)
  305. return new byte[0];
  306. int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
  307. // Trim illegal chars from start
  308. while (sIx < eIx && IA[sArr[sIx]] < 0)
  309. sIx++;
  310. // Trim illegal chars from end
  311. while (eIx > 0 && IA[sArr[eIx]] < 0)
  312. eIx--;
  313. // get the padding count (=) (0, 1 or 2)
  314. int pad = sArr[eIx] == '=' ? (sArr[eIx - 1] == '=' ? 2 : 1) : 0; // Count '=' at end.
  315. int cCnt = eIx - sIx + 1; // Content count including possible separators
  316. int sepCnt = sLen > 76 ? (sArr[76] == '\r' ? cCnt / 78 : 0) << 1 : 0;
  317. int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
  318. byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
  319. // Decode all but the last 0 - 2 bytes.
  320. int d = 0;
  321. for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) {
  322. // Assemble three bytes into an int from four "valid" characters.
  323. int i = IA[sArr[sIx++]] << 18 | IA[sArr[sIx++]] << 12 | IA[sArr[sIx++]] << 6 | IA[sArr[sIx++]];
  324. // Add the bytes
  325. dArr[d++] = (byte) (i >> 16);
  326. dArr[d++] = (byte) (i >> 8);
  327. dArr[d++] = (byte) i;
  328. // If line separator, jump over it.
  329. if (sepCnt > 0 && ++cc == 19) {
  330. sIx += 2;
  331. cc = 0;
  332. }
  333. }
  334. if (d < len) {
  335. // Decode last 1-3 bytes (incl '=') into 1-3 bytes
  336. int i = 0;
  337. for (int j = 0; sIx <= eIx - pad; j++)
  338. i |= IA[sArr[sIx++]] << (18 - j * 6);
  339. for (int r = 16; d < len; r -= 8)
  340. dArr[d++] = (byte) (i >> r);
  341. }
  342. return dArr;
  343. }
  344. // ****************************************************************************************
  345. // * byte[] version
  346. // ****************************************************************************************
  347. /**
  348. * Encodes a raw byte array into a BASE64 <code>byte[]</code> representation i accordance with RFC 2045.
  349. *
  350. * @param sArr
  351. * The bytes to convert. If <code>null</code> or length 0 an empty array will be returned.
  352. * @param lineSep
  353. * Optional "\r\n" after 76 characters, unless end of file.<br>
  354. * No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a little
  355. * faster.
  356. * @return A BASE64 encoded array. Never <code>null</code>.
  357. */
  358. public final static byte[] encodeToByte(byte[] sArr, boolean lineSep) {
  359. // Check special case
  360. int sLen = sArr != null ? sArr.length : 0;
  361. if (sLen == 0)
  362. return new byte[0];
  363. int eLen = (sLen / 3) * 3; // Length of even 24-bits.
  364. int cCnt = ((sLen - 1) / 3 + 1) << 2; // Returned character count
  365. int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of returned array
  366. byte[] dArr = new byte[dLen];
  367. // Encode even 24-bits
  368. for (int s = 0, d = 0, cc = 0; s < eLen;) {
  369. // Copy next three bytes into lower 24 bits of int, paying attension to sign.
  370. int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | (sArr[s++] & 0xff);
  371. // Encode the int into four chars
  372. dArr[d++] = (byte) CA[(i >>> 18) & 0x3f];
  373. dArr[d++] = (byte) CA[(i >>> 12) & 0x3f];
  374. dArr[d++] = (byte) CA[(i >>> 6) & 0x3f];
  375. dArr[d++] = (byte) CA[i & 0x3f];
  376. // Add optional line separator
  377. if (lineSep && ++cc == 19 && d < dLen - 2) {
  378. dArr[d++] = '\r';
  379. dArr[d++] = '\n';
  380. cc = 0;
  381. }
  382. }
  383. // Pad and encode last bits if source isn't an even 24 bits.
  384. int left = sLen - eLen; // 0 - 2.
  385. if (left > 0) {
  386. // Prepare the int
  387. int i = ((sArr[eLen] & 0xff) << 10) | (left == 2 ? ((sArr[sLen - 1] & 0xff) << 2) : 0);
  388. // Set last four chars
  389. dArr[dLen - 4] = (byte) CA[i >> 12];
  390. dArr[dLen - 3] = (byte) CA[(i >>> 6) & 0x3f];
  391. dArr[dLen - 2] = left == 2 ? (byte) CA[i & 0x3f] : (byte) '=';
  392. dArr[dLen - 1] = '=';
  393. }
  394. return dArr;
  395. }
  396. /**
  397. * Decodes a BASE64 encoded byte array. All illegal characters will be ignored and can handle both arrays with and
  398. * without line separators.
  399. *
  400. * @param sArr
  401. * The source array. Length 0 will return an empty array. <code>null</code> will throw an exception.
  402. * @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters
  403. * (including '=') isn't divideable by 4. (I.e. definitely corrupted).
  404. */
  405. public final static byte[] decode(byte[] sArr) {
  406. // Check special case
  407. int sLen = sArr.length;
  408. // Count illegal characters (including '\r', '\n') to know what size the returned array will be,
  409. // so we don't have to reallocate & copy it later.
  410. int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
  411. for (int i = 0; i < sLen; i++)
  412. // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out.
  413. if (IA[sArr[i] & 0xff] < 0)
  414. sepCnt++;
  415. // Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
  416. if ((sLen - sepCnt) % 4 != 0)
  417. return null;
  418. int pad = 0;
  419. for (int i = sLen; i > 1 && IA[sArr[--i] & 0xff] <= 0;)
  420. if (sArr[i] == '=')
  421. pad++;
  422. int len = ((sLen - sepCnt) * 6 >> 3) - pad;
  423. byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
  424. for (int s = 0, d = 0; d < len;) {
  425. // Assemble three bytes into an int from four "valid" characters.
  426. int i = 0;
  427. for (int j = 0; j < 4; j++) { // j only increased if a valid char was found.
  428. int c = IA[sArr[s++] & 0xff];
  429. if (c >= 0)
  430. i |= c << (18 - j * 6);
  431. else
  432. j--;
  433. }
  434. // Add the bytes
  435. dArr[d++] = (byte) (i >> 16);
  436. if (d < len) {
  437. dArr[d++] = (byte) (i >> 8);
  438. if (d < len)
  439. dArr[d++] = (byte) i;
  440. }
  441. }
  442. return dArr;
  443. }
  444. /**
  445. * Decodes a BASE64 encoded byte array that is known to be resonably well formatted. The method is about twice as
  446. * fast as {@link #decode(byte[])}. The preconditions are:<br>
  447. * + The array must have a line length of 76 chars OR no line separators at all (one line).<br>
  448. * + Line separator must be "\r\n", as specified in RFC 2045 + The array must not contain illegal characters within
  449. * the encoded string<br>
  450. * + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br>
  451. *
  452. * @param sArr
  453. * The source array. Length 0 will return an empty array. <code>null</code> will throw an exception.
  454. * @return The decoded array of bytes. May be of length 0.
  455. */
  456. public final static byte[] decodeFast(byte[] sArr) {
  457. // Check special case
  458. int sLen = sArr.length;
  459. if (sLen == 0)
  460. return new byte[0];
  461. int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
  462. // Trim illegal chars from start
  463. while (sIx < eIx && IA[sArr[sIx] & 0xff] < 0)
  464. sIx++;
  465. // Trim illegal chars from end
  466. while (eIx > 0 && IA[sArr[eIx] & 0xff] < 0)
  467. eIx--;
  468. // get the padding count (=) (0, 1 or 2)
  469. int pad = sArr[eIx] == '=' ? (sArr[eIx - 1] == '=' ? 2 : 1) : 0; // Count '=' at end.
  470. int cCnt = eIx - sIx + 1; // Content count including possible separators
  471. int sepCnt = sLen > 76 ? (sArr[76] == '\r' ? cCnt / 78 : 0) << 1 : 0;
  472. int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
  473. byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
  474. // Decode all but the last 0 - 2 bytes.
  475. int d = 0;
  476. for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) {
  477. // Assemble three bytes into an int from four "valid" characters.
  478. int i = IA[sArr[sIx++]] << 18 | IA[sArr[sIx++]] << 12 | IA[sArr[sIx++]] << 6 | IA[sArr[sIx++]];
  479. // Add the bytes
  480. dArr[d++] = (byte) (i >> 16);
  481. dArr[d++] = (byte) (i >> 8);
  482. dArr[d++] = (byte) i;
  483. // If line separator, jump over it.
  484. if (sepCnt > 0 && ++cc == 19) {
  485. sIx += 2;
  486. cc = 0;
  487. }
  488. }
  489. if (d < len) {
  490. // Decode last 1-3 bytes (incl '=') into 1-3 bytes
  491. int i = 0;
  492. for (int j = 0; sIx <= eIx - pad; j++)
  493. i |= IA[sArr[sIx++]] << (18 - j * 6);
  494. for (int r = 16; d < len; r -= 8)
  495. dArr[d++] = (byte) (i >> r);
  496. }
  497. return dArr;
  498. }
  499. // ****************************************************************************************
  500. // * String version
  501. // ****************************************************************************************
  502. /**
  503. * Encodes a raw byte array into a BASE64 <code>String</code> representation i accordance with RFC 2045.
  504. *
  505. * @param sArr
  506. * The bytes to convert. If <code>null</code> or length 0 an empty array will be returned.
  507. * @param lineSep
  508. * Optional "\r\n" after 76 characters, unless end of file.<br>
  509. * No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a little
  510. * faster.
  511. * @return A BASE64 encoded array. Never <code>null</code>.
  512. */
  513. public final static String encodeToString(byte[] sArr, boolean lineSep) {
  514. // Reuse char[] since we can't create a String incrementally anyway and StringBuffer/Builder would be slower.
  515. return new String(encodeToChar(sArr, lineSep));
  516. }
  517. /**
  518. * Decodes a BASE64 encoded <code>String</code>. All illegal characters will be ignored and can handle both strings
  519. * with and without line separators.<br>
  520. * <b>Note!</b> It can be up to about 2x the speed to call <code>decode(str.toCharArray())</code> instead. That will
  521. * create a temporary array though. This version will use <code>str.charAt(i)</code> to iterate the string.
  522. *
  523. * @param str
  524. * The source string. <code>null</code> or length 0 will return an empty array.
  525. * @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters
  526. * (including '=') isn't divideable by 4. (I.e. definitely corrupted).
  527. */
  528. public final static byte[] decode(String str) {
  529. // Check special case
  530. int sLen = str != null ? str.length() : 0;
  531. if (sLen == 0)
  532. return new byte[0];
  533. // Count illegal characters (including '\r', '\n') to know what size the returned array will be,
  534. // so we don't have to reallocate & copy it later.
  535. int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
  536. for (int i = 0; i < sLen; i++)
  537. // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out.
  538. if (IA[str.charAt(i)] < 0)
  539. sepCnt++;
  540. // Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
  541. if ((sLen - sepCnt) % 4 != 0)
  542. return null;
  543. // Count '=' at end
  544. int pad = 0;
  545. for (int i = sLen; i > 1 && IA[str.charAt(--i)] <= 0;)
  546. if (str.charAt(i) == '=')
  547. pad++;
  548. int len = ((sLen - sepCnt) * 6 >> 3) - pad;
  549. byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
  550. for (int s = 0, d = 0; d < len;) {
  551. // Assemble three bytes into an int from four "valid" characters.
  552. int i = 0;
  553. for (int j = 0; j < 4; j++) { // j only increased if a valid char was found.
  554. int c = IA[str.charAt(s++)];
  555. if (c >= 0)
  556. i |= c << (18 - j * 6);
  557. else
  558. j--;
  559. }
  560. // Add the bytes
  561. dArr[d++] = (byte) (i >> 16);
  562. if (d < len) {
  563. dArr[d++] = (byte) (i >> 8);
  564. if (d < len)
  565. dArr[d++] = (byte) i;
  566. }
  567. }
  568. return dArr;
  569. }
  570. /**
  571. * Decodes a BASE64 encoded string that is known to be resonably well formatted. The method is about twice as fast
  572. * as {@link #decode(String)}. The preconditions are:<br>
  573. * + The array must have a line length of 76 chars OR no line separators at all (one line).<br>
  574. * + Line separator must be "\r\n", as specified in RFC 2045 + The array must not contain illegal characters within
  575. * the encoded string<br>
  576. * + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br>
  577. *
  578. * @param s
  579. * The source string. Length 0 will return an empty array. <code>null</code> will throw an exception.
  580. * @return The decoded array of bytes. May be of length 0.
  581. */
  582. public final static byte[] decodeFast(String s) {
  583. // Check special case
  584. int sLen = s.length();
  585. if (sLen == 0)
  586. return new byte[0];
  587. int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
  588. // Trim illegal chars from start
  589. while (sIx < eIx && IA[s.charAt(sIx) & 0xff] < 0)
  590. sIx++;
  591. // Trim illegal chars from end
  592. while (eIx > 0 && IA[s.charAt(eIx) & 0xff] < 0)
  593. eIx--;
  594. // get the padding count (=) (0, 1 or 2)
  595. int pad = s.charAt(eIx) == '=' ? (s.charAt(eIx - 1) == '=' ? 2 : 1) : 0; // Count '=' at end.
  596. int cCnt = eIx - sIx + 1; // Content count including possible separators
  597. int sepCnt = sLen > 76 ? (s.charAt(76) == '\r' ? cCnt / 78 : 0) << 1 : 0;
  598. int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
  599. byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
  600. // Decode all but the last 0 - 2 bytes.
  601. int d = 0;
  602. for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) {
  603. // Assemble three bytes into an int from four "valid" characters.
  604. int i = IA[s.charAt(sIx++)] << 18 | IA[s.charAt(sIx++)] << 12 | IA[s.charAt(sIx++)] << 6 | IA[s.charAt(sIx++)];
  605. // Add the bytes
  606. dArr[d++] = (byte) (i >> 16);
  607. dArr[d++] = (byte) (i >> 8);
  608. dArr[d++] = (byte) i;
  609. // If line separator, jump over it.
  610. if (sepCnt > 0 && ++cc == 19) {
  611. sIx += 2;
  612. cc = 0;
  613. }
  614. }
  615. if (d < len) {
  616. // Decode last 1-3 bytes (incl '=') into 1-3 bytes
  617. int i = 0;
  618. for (int j = 0; sIx <= eIx - pad; j++)
  619. i |= IA[s.charAt(sIx++)] << (18 - j * 6);
  620. for (int r = 16; d < len; r -= 8)
  621. dArr[d++] = (byte) (i >> r);
  622. }
  623. return dArr;
  624. }
  625. }
  626. }