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 9.0KB

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