You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Base64.java 8.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. //
  2. // NOTE: The following source code is heavily derived from the
  3. // iHarder.net public domain Base64 library. See the original at
  4. // http://iharder.sourceforge.net/current/java/base64/
  5. //
  6. package org.eclipse.jgit.util;
  7. import static java.nio.charset.StandardCharsets.UTF_8;
  8. import java.text.MessageFormat;
  9. import java.util.Arrays;
  10. import org.eclipse.jgit.internal.JGitText;
  11. /**
  12. * Encodes and decodes to and from Base64 notation.
  13. * <p>
  14. * I am placing this code in the Public Domain. Do with it as you will. This
  15. * software comes with no guarantees or warranties but with plenty of
  16. * well-wishing instead! Please visit
  17. * <a href="http://iharder.net/base64">http://iharder.net/base64</a>
  18. * periodically to check for updates or to contribute improvements.
  19. * </p>
  20. *
  21. * @author Robert Harder
  22. * @author rob@iharder.net
  23. */
  24. public class Base64 {
  25. /** The equals sign (=) as a byte. */
  26. private static final byte EQUALS_SIGN = (byte) '=';
  27. /** Indicates equals sign in encoding. */
  28. private static final byte EQUALS_SIGN_DEC = -1;
  29. /** Indicates white space in encoding. */
  30. private static final byte WHITE_SPACE_DEC = -2;
  31. /** Indicates an invalid byte during decoding. */
  32. private static final byte INVALID_DEC = -3;
  33. /** The 64 valid Base64 values. */
  34. private static final byte[] ENC;
  35. /**
  36. * Translates a Base64 value to either its 6-bit reconstruction value or a
  37. * negative number indicating some other meaning. The table is only 7 bits
  38. * wide, as the 8th bit is discarded during decoding.
  39. */
  40. private static final byte[] DEC;
  41. static {
  42. ENC = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ" // //$NON-NLS-1$
  43. + "abcdefghijklmnopqrstuvwxyz" // //$NON-NLS-1$
  44. + "0123456789" // //$NON-NLS-1$
  45. + "+/" // //$NON-NLS-1$
  46. ).getBytes(UTF_8);
  47. DEC = new byte[128];
  48. Arrays.fill(DEC, INVALID_DEC);
  49. for (int i = 0; i < 64; i++)
  50. DEC[ENC[i]] = (byte) i;
  51. DEC[EQUALS_SIGN] = EQUALS_SIGN_DEC;
  52. DEC['\t'] = WHITE_SPACE_DEC;
  53. DEC['\n'] = WHITE_SPACE_DEC;
  54. DEC['\r'] = WHITE_SPACE_DEC;
  55. DEC[' '] = WHITE_SPACE_DEC;
  56. }
  57. /** Defeats instantiation. */
  58. private Base64() {
  59. // Suppress empty block warning.
  60. }
  61. /**
  62. * Encodes up to three bytes of the array <var>source</var> and writes the
  63. * resulting four Base64 bytes to <var>destination</var>. The source and
  64. * destination arrays can be manipulated anywhere along their length by
  65. * specifying <var>srcOffset</var> and <var>destOffset</var>. This method
  66. * does not check to make sure your arrays are large enough to accommodate
  67. * <var>srcOffset</var> + 3 for the <var>source</var> array or
  68. * <var>destOffset</var> + 4 for the <var>destination</var> array. The
  69. * actual number of significant bytes in your array is given by
  70. * <var>numSigBytes</var>.
  71. *
  72. * @param source
  73. * the array to convert
  74. * @param srcOffset
  75. * the index where conversion begins
  76. * @param numSigBytes
  77. * the number of significant bytes in your array
  78. * @param destination
  79. * the array to hold the conversion
  80. * @param destOffset
  81. * the index where output will be put
  82. */
  83. private static void encode3to4(byte[] source, int srcOffset,
  84. int numSigBytes, byte[] destination, int destOffset) {
  85. // We have to shift left 24 in order to flush out the 1's that appear
  86. // when Java treats a value as negative that is cast from a byte.
  87. int inBuff = 0;
  88. switch (numSigBytes) {
  89. case 3:
  90. inBuff |= (source[srcOffset + 2] << 24) >>> 24;
  91. //$FALL-THROUGH$
  92. case 2:
  93. inBuff |= (source[srcOffset + 1] << 24) >>> 16;
  94. //$FALL-THROUGH$
  95. case 1:
  96. inBuff |= (source[srcOffset] << 24) >>> 8;
  97. }
  98. switch (numSigBytes) {
  99. case 3:
  100. destination[destOffset] = ENC[(inBuff >>> 18)];
  101. destination[destOffset + 1] = ENC[(inBuff >>> 12) & 0x3f];
  102. destination[destOffset + 2] = ENC[(inBuff >>> 6) & 0x3f];
  103. destination[destOffset + 3] = ENC[(inBuff) & 0x3f];
  104. break;
  105. case 2:
  106. destination[destOffset] = ENC[(inBuff >>> 18)];
  107. destination[destOffset + 1] = ENC[(inBuff >>> 12) & 0x3f];
  108. destination[destOffset + 2] = ENC[(inBuff >>> 6) & 0x3f];
  109. destination[destOffset + 3] = EQUALS_SIGN;
  110. break;
  111. case 1:
  112. destination[destOffset] = ENC[(inBuff >>> 18)];
  113. destination[destOffset + 1] = ENC[(inBuff >>> 12) & 0x3f];
  114. destination[destOffset + 2] = EQUALS_SIGN;
  115. destination[destOffset + 3] = EQUALS_SIGN;
  116. break;
  117. }
  118. }
  119. /**
  120. * Encodes a byte array into Base64 notation.
  121. *
  122. * @param source
  123. * The data to convert
  124. * @return encoded base64 representation of source.
  125. */
  126. public static String encodeBytes(byte[] source) {
  127. return encodeBytes(source, 0, source.length);
  128. }
  129. /**
  130. * Encodes a byte array into Base64 notation.
  131. *
  132. * @param source
  133. * The data to convert
  134. * @param off
  135. * Offset in array where conversion should begin
  136. * @param len
  137. * Length of data to convert
  138. * @return encoded base64 representation of source.
  139. */
  140. public static String encodeBytes(byte[] source, int off, int len) {
  141. final int len43 = len * 4 / 3;
  142. byte[] outBuff = new byte[len43 + ((len % 3) > 0 ? 4 : 0)];
  143. int d = 0;
  144. int e = 0;
  145. int len2 = len - 2;
  146. for (; d < len2; d += 3, e += 4)
  147. encode3to4(source, d + off, 3, outBuff, e);
  148. if (d < len) {
  149. encode3to4(source, d + off, len - d, outBuff, e);
  150. e += 4;
  151. }
  152. return new String(outBuff, 0, e, UTF_8);
  153. }
  154. /**
  155. * Decodes four bytes from array <var>source</var> and writes the resulting
  156. * bytes (up to three of them) to <var>destination</var>. The source and
  157. * destination arrays can be manipulated anywhere along their length by
  158. * specifying <var>srcOffset</var> and <var>destOffset</var>. This method
  159. * does not check to make sure your arrays are large enough to accommodate
  160. * <var>srcOffset</var> + 4 for the <var>source</var> array or
  161. * <var>destOffset</var> + 3 for the <var>destination</var> array. This
  162. * method returns the actual number of bytes that were converted from the
  163. * Base64 encoding.
  164. *
  165. * @param source
  166. * the array to convert
  167. * @param srcOffset
  168. * the index where conversion begins
  169. * @param destination
  170. * the array to hold the conversion
  171. * @param destOffset
  172. * the index where output will be put
  173. * @return the number of decoded bytes converted
  174. */
  175. private static int decode4to3(byte[] source, int srcOffset,
  176. byte[] destination, int destOffset) {
  177. // Example: Dk==
  178. if (source[srcOffset + 2] == EQUALS_SIGN) {
  179. int outBuff = ((DEC[source[srcOffset]] & 0xFF) << 18)
  180. | ((DEC[source[srcOffset + 1]] & 0xFF) << 12);
  181. destination[destOffset] = (byte) (outBuff >>> 16);
  182. return 1;
  183. }
  184. // Example: DkL=
  185. else if (source[srcOffset + 3] == EQUALS_SIGN) {
  186. int outBuff = ((DEC[source[srcOffset]] & 0xFF) << 18)
  187. | ((DEC[source[srcOffset + 1]] & 0xFF) << 12)
  188. | ((DEC[source[srcOffset + 2]] & 0xFF) << 6);
  189. destination[destOffset] = (byte) (outBuff >>> 16);
  190. destination[destOffset + 1] = (byte) (outBuff >>> 8);
  191. return 2;
  192. }
  193. // Example: DkLE
  194. else {
  195. int outBuff = ((DEC[source[srcOffset]] & 0xFF) << 18)
  196. | ((DEC[source[srcOffset + 1]] & 0xFF) << 12)
  197. | ((DEC[source[srcOffset + 2]] & 0xFF) << 6)
  198. | ((DEC[source[srcOffset + 3]] & 0xFF));
  199. destination[destOffset] = (byte) (outBuff >> 16);
  200. destination[destOffset + 1] = (byte) (outBuff >> 8);
  201. destination[destOffset + 2] = (byte) (outBuff);
  202. return 3;
  203. }
  204. }
  205. /**
  206. * Low-level decoding ASCII characters from a byte array.
  207. *
  208. * @param source
  209. * The Base64 encoded data
  210. * @param off
  211. * The offset of where to begin decoding
  212. * @param len
  213. * The length of characters to decode
  214. * @return decoded data
  215. * @throws java.lang.IllegalArgumentException
  216. * the input is not a valid Base64 sequence.
  217. */
  218. public static byte[] decode(byte[] source, int off, int len) {
  219. byte[] outBuff = new byte[len * 3 / 4]; // Upper limit on size of output
  220. int outBuffPosn = 0;
  221. byte[] b4 = new byte[4];
  222. int b4Posn = 0;
  223. for (int i = off; i < off + len; i++) {
  224. byte sbiCrop = (byte) (source[i] & 0x7f);
  225. byte sbiDecode = DEC[sbiCrop];
  226. if (EQUALS_SIGN_DEC <= sbiDecode) {
  227. b4[b4Posn++] = sbiCrop;
  228. if (b4Posn > 3) {
  229. outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn);
  230. b4Posn = 0;
  231. // If that was the equals sign, break out of 'for' loop
  232. if (sbiCrop == EQUALS_SIGN)
  233. break;
  234. }
  235. } else if (sbiDecode != WHITE_SPACE_DEC)
  236. throw new IllegalArgumentException(MessageFormat.format(
  237. JGitText.get().badBase64InputCharacterAt,
  238. Integer.valueOf(i), Integer.valueOf(source[i] & 0xff)));
  239. }
  240. if (outBuff.length == outBuffPosn)
  241. return outBuff;
  242. byte[] out = new byte[outBuffPosn];
  243. System.arraycopy(outBuff, 0, out, 0, outBuffPosn);
  244. return out;
  245. }
  246. /**
  247. * Decodes data from Base64 notation.
  248. *
  249. * @param s
  250. * the string to decode
  251. * @return the decoded data
  252. */
  253. public static byte[] decode(String s) {
  254. byte[] bytes = s.getBytes(UTF_8);
  255. return decode(bytes, 0, bytes.length);
  256. }
  257. }