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

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