221a53ebbfaa8dbb93427d21de7362427a2702a5.svn-base 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063
  1. package com.chinacreator.videoalliance.order.util;
  2. import java.io.UnsupportedEncodingException;
  3. import java.util.Arrays;
  4. public class Base64 extends BaseNCodec {
  5. /**
  6. * BASE32 characters are 6 bits in length. They are formed by taking a block
  7. * of 3 octets to form a 24-bit string, which is converted into 4 BASE64
  8. * characters.
  9. */
  10. private static final int BITS_PER_ENCODED_BYTE = 6;
  11. private static final int BYTES_PER_UNENCODED_BLOCK = 3;
  12. private static final int BYTES_PER_ENCODED_BLOCK = 4;
  13. /**
  14. * Chunk separator per RFC 2045 section 2.1.
  15. *
  16. * <p>
  17. * N.B. The next major release may break compatibility and make this field
  18. * private.
  19. * </p>
  20. */
  21. static final byte[] CHUNK_SEPARATOR = { '\r', '\n' };
  22. /**
  23. * This array is a lookup table that translates 6-bit positive integer index
  24. * values into their "Base64 Alphabet" equivalents as specified in Table 1
  25. * of RFC 2045.
  26. */
  27. private static final byte[] STANDARD_ENCODE_TABLE = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' };
  28. /**
  29. * This is a copy of the STANDARD_ENCODE_TABLE above, but with + and /
  30. * changed to - and _ to make the encoded Base64 results more URL-SAFE. This
  31. * table is only used when the Base64's mode is set to URL-SAFE.
  32. */
  33. private static final byte[] URL_SAFE_ENCODE_TABLE = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_' };
  34. /**
  35. * This array is a lookup table that translates Unicode characters drawn
  36. * from the "Base64 Alphabet" (as specified in Table 1 of RFC 2045) into
  37. * their 6-bit positive integer equivalents. Characters that are not in the
  38. * Base64 alphabet but fall within the bounds of the array are translated to
  39. * -1.
  40. *
  41. * Note: '+' and '-' both decode to 62. '/' and '_' both decode to 63. This
  42. * means decoder seamlessly handles both URL_SAFE and STANDARD base64. (The
  43. * encoder, on the other hand, needs to know ahead of time what to emit).
  44. *
  45. */
  46. private static final byte[] DECODE_TABLE = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
  47. 44, 45, 46, 47, 48, 49, 50, 51 };
  48. /**
  49. * Base64 uses 6-bit fields.
  50. */
  51. /** Mask used to extract 6 bits, used when encoding */
  52. private static final int MASK_6BITS = 0x3f;
  53. // The static final fields above are used for the original static byte[]
  54. // methods on Base64.
  55. // The private member fields below are used with the new streaming approach,
  56. // which requires
  57. // some state be preserved between calls of encode() and decode().
  58. /**
  59. * Encode table to use: either STANDARD or URL_SAFE. Note: the DECODE_TABLE
  60. * above remains static because it is able to decode both STANDARD and
  61. * URL_SAFE streams, but the encodeTable must be a member variable so we can
  62. * switch between the two modes.
  63. */
  64. private final byte[] encodeTable;
  65. // Only one decode table currently; keep for consistency with Base32 code
  66. private final byte[] decodeTable = DECODE_TABLE;
  67. /**
  68. * Line separator for encoding. Not used when decoding. Only used if
  69. * lineLength > 0.
  70. */
  71. private final byte[] lineSeparator;
  72. /**
  73. * Convenience variable to help us determine when our buffer is going to run
  74. * out of room and needs resizing.
  75. * <code>decodeSize = 3 + lineSeparator.length;</code>
  76. */
  77. private final int decodeSize;
  78. /**
  79. * Convenience variable to help us determine when our buffer is going to run
  80. * out of room and needs resizing.
  81. * <code>encodeSize = 4 + lineSeparator.length;</code>
  82. */
  83. private final int encodeSize;
  84. /**
  85. * Creates a Base64 codec used for decoding (all modes) and encoding in
  86. * URL-unsafe mode.
  87. * <p>
  88. * When encoding the line length is 0 (no chunking), and the encoding table
  89. * is STANDARD_ENCODE_TABLE.
  90. * </p>
  91. *
  92. * <p>
  93. * When decoding all variants are supported.
  94. * </p>
  95. */
  96. public Base64() {
  97. this(0);
  98. }
  99. /**
  100. * Creates a Base64 codec used for decoding (all modes) and encoding in the
  101. * given URL-safe mode.
  102. * <p>
  103. * When encoding the line length is 76, the line separator is CRLF, and the
  104. * encoding table is STANDARD_ENCODE_TABLE.
  105. * </p>
  106. *
  107. * <p>
  108. * When decoding all variants are supported.
  109. * </p>
  110. *
  111. * @param urlSafe
  112. * if {@code true}, URL-safe encoding is used. In most cases this
  113. * should be set to {@code false}.
  114. * @since 1.4
  115. */
  116. public Base64(final boolean urlSafe) {
  117. this(MIME_CHUNK_SIZE, CHUNK_SEPARATOR, urlSafe);
  118. }
  119. /**
  120. * Creates a Base64 codec used for decoding (all modes) and encoding in
  121. * URL-unsafe mode.
  122. * <p>
  123. * When encoding the line length is given in the constructor, the line
  124. * separator is CRLF, and the encoding table is STANDARD_ENCODE_TABLE.
  125. * </p>
  126. * <p>
  127. * Line lengths that aren't multiples of 4 will still essentially end up
  128. * being multiples of 4 in the encoded data.
  129. * </p>
  130. * <p>
  131. * When decoding all variants are supported.
  132. * </p>
  133. *
  134. * @param lineLength
  135. * Each line of encoded data will be at most of the given length
  136. * (rounded down to nearest multiple of 4). If lineLength <= 0,
  137. * then the output will not be divided into lines (chunks).
  138. * Ignored when decoding.
  139. */
  140. public Base64(final int lineLength) {
  141. this(lineLength, CHUNK_SEPARATOR);
  142. }
  143. /**
  144. * Creates a Base64 codec used for decoding (all modes) and encoding in
  145. * URL-unsafe mode.
  146. * <p>
  147. * When encoding the line length and line separator are given in the
  148. * constructor, and the encoding table is STANDARD_ENCODE_TABLE.
  149. * </p>
  150. * <p>
  151. * Line lengths that aren't multiples of 4 will still essentially end up
  152. * being multiples of 4 in the encoded data.
  153. * </p>
  154. * <p>
  155. * When decoding all variants are supported.
  156. * </p>
  157. *
  158. * @param lineLength
  159. * Each line of encoded data will be at most of the given length
  160. * (rounded down to nearest multiple of 4). If lineLength <= 0,
  161. * then the output will not be divided into lines (chunks).
  162. * Ignored when decoding.
  163. * @param lineSeparator
  164. * Each line of encoded data will end with this sequence of
  165. * bytes.
  166. * @throws IllegalArgumentException
  167. * Thrown when the provided lineSeparator included some base64
  168. * characters.
  169. */
  170. public Base64(final int lineLength, final byte[] lineSeparator) {
  171. this(lineLength, lineSeparator, false);
  172. }
  173. /**
  174. * Creates a Base64 codec used for decoding (all modes) and encoding in
  175. * URL-unsafe mode.
  176. * <p>
  177. * When encoding the line length and line separator are given in the
  178. * constructor, and the encoding table is STANDARD_ENCODE_TABLE.
  179. * </p>
  180. * <p>
  181. * Line lengths that aren't multiples of 4 will still essentially end up
  182. * being multiples of 4 in the encoded data.
  183. * </p>
  184. * <p>
  185. * When decoding all variants are supported.
  186. * </p>
  187. *
  188. * @param lineLength
  189. * Each line of encoded data will be at most of the given length
  190. * (rounded down to nearest multiple of 4). If lineLength <= 0,
  191. * then the output will not be divided into lines (chunks).
  192. * Ignored when decoding.
  193. * @param lineSeparator
  194. * Each line of encoded data will end with this sequence of
  195. * bytes.
  196. * @param urlSafe
  197. * Instead of emitting '+' and '/' we emit '-' and '_'
  198. * respectively. urlSafe is only applied to encode operations.
  199. * Decoding seamlessly handles both modes. <b>Note: no padding is
  200. * added when using the URL-safe alphabet.</b>
  201. * @throws IllegalArgumentException
  202. * The provided lineSeparator included some base64 characters.
  203. * That's not going to work!
  204. */
  205. public Base64(final int lineLength, final byte[] lineSeparator, final boolean urlSafe) {
  206. super(BYTES_PER_UNENCODED_BLOCK, BYTES_PER_ENCODED_BLOCK, lineLength, lineSeparator == null ? 0 : lineSeparator.length);
  207. // TODO could be simplified if there is no requirement to reject invalid
  208. // line sep when length <=0
  209. // @see test case Base64Test.testConstructors()
  210. if (lineSeparator != null) {
  211. if (containsAlphabetOrPad(lineSeparator)) {
  212. try {
  213. final String sep = new String(lineSeparator, "UTF-8");
  214. throw new IllegalArgumentException("lineSeparator must not contain base64 characters: [" + sep + "]");
  215. } catch (UnsupportedEncodingException e) {
  216. e.printStackTrace();
  217. }
  218. }
  219. if (lineLength > 0) { // null line-sep forces no chunking rather
  220. // than throwing IAE
  221. this.encodeSize = BYTES_PER_ENCODED_BLOCK + lineSeparator.length;
  222. this.lineSeparator = new byte[lineSeparator.length];
  223. System.arraycopy(lineSeparator, 0, this.lineSeparator, 0, lineSeparator.length);
  224. } else {
  225. this.encodeSize = BYTES_PER_ENCODED_BLOCK;
  226. this.lineSeparator = null;
  227. }
  228. } else {
  229. this.encodeSize = BYTES_PER_ENCODED_BLOCK;
  230. this.lineSeparator = null;
  231. }
  232. this.decodeSize = this.encodeSize - 1;
  233. this.encodeTable = urlSafe ? URL_SAFE_ENCODE_TABLE : STANDARD_ENCODE_TABLE;
  234. }
  235. /**
  236. * <p>
  237. * Encodes all of the provided data, starting at inPos, for inAvail bytes.
  238. * Must be called at least twice: once with the data to encode, and once
  239. * with inAvail set to "-1" to alert encoder that EOF has been reached, to
  240. * flush last remaining bytes (if not multiple of 3).
  241. * </p>
  242. * <p>
  243. * <b>Note: no padding is added when encoding using the URL-safe
  244. * alphabet.</b>
  245. * </p>
  246. *
  247. * @param in
  248. * byte[] array of binary data to base64 encode.
  249. * @param inPos
  250. * Position to start reading data from.
  251. * @param inAvail
  252. * Amount of bytes available from input for encoding.
  253. * @param context
  254. * the context to be used
  255. */
  256. @Override
  257. void encode(final byte[] in, int inPos, final int inAvail, final Context context) {
  258. if (context.eof) {
  259. return;
  260. }
  261. // inAvail < 0 is how we're informed of EOF in the underlying data we're
  262. // encoding.
  263. if (inAvail < 0) {
  264. context.eof = true;
  265. if (0 == context.modulus && lineLength == 0) {
  266. return; // no leftovers to process and not using chunking
  267. }
  268. final byte[] buffer = ensureBufferSize(encodeSize, context);
  269. final int savedPos = context.pos;
  270. switch (context.modulus) { // 0-2
  271. case 0: // nothing to do here
  272. break;
  273. case 1: // 8 bits = 6 + 2
  274. // top 6 bits:
  275. buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 2) & MASK_6BITS];
  276. // remaining 2:
  277. buffer[context.pos++] = encodeTable[(context.ibitWorkArea << 4) & MASK_6BITS];
  278. // URL-SAFE skips the padding to further reduce size.
  279. if (encodeTable == STANDARD_ENCODE_TABLE) {
  280. buffer[context.pos++] = PAD;
  281. buffer[context.pos++] = PAD;
  282. }
  283. break;
  284. case 2: // 16 bits = 6 + 6 + 4
  285. buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 10) & MASK_6BITS];
  286. buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 4) & MASK_6BITS];
  287. buffer[context.pos++] = encodeTable[(context.ibitWorkArea << 2) & MASK_6BITS];
  288. // URL-SAFE skips the padding to further reduce size.
  289. if (encodeTable == STANDARD_ENCODE_TABLE) {
  290. buffer[context.pos++] = PAD;
  291. }
  292. break;
  293. default:
  294. throw new IllegalStateException("Impossible modulus " + context.modulus);
  295. }
  296. context.currentLinePos += context.pos - savedPos; // keep track of
  297. // current line
  298. // position
  299. // if currentPos == 0 we are at the start of a line, so don't add
  300. // CRLF
  301. if (lineLength > 0 && context.currentLinePos > 0) {
  302. System.arraycopy(lineSeparator, 0, buffer, context.pos, lineSeparator.length);
  303. context.pos += lineSeparator.length;
  304. }
  305. } else {
  306. for (int i = 0; i < inAvail; i++) {
  307. final byte[] buffer = ensureBufferSize(encodeSize, context);
  308. context.modulus = (context.modulus + 1) % BYTES_PER_UNENCODED_BLOCK;
  309. int b = in[inPos++];
  310. if (b < 0) {
  311. b += 256;
  312. }
  313. context.ibitWorkArea = (context.ibitWorkArea << 8) + b; // BITS_PER_BYTE
  314. if (0 == context.modulus) { // 3 bytes = 24 bits = 4 * 6 bits to
  315. // extract
  316. buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 18) & MASK_6BITS];
  317. buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 12) & MASK_6BITS];
  318. buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 6) & MASK_6BITS];
  319. buffer[context.pos++] = encodeTable[context.ibitWorkArea & MASK_6BITS];
  320. context.currentLinePos += BYTES_PER_ENCODED_BLOCK;
  321. if (lineLength > 0 && lineLength <= context.currentLinePos) {
  322. System.arraycopy(lineSeparator, 0, buffer, context.pos, lineSeparator.length);
  323. context.pos += lineSeparator.length;
  324. context.currentLinePos = 0;
  325. }
  326. }
  327. }
  328. }
  329. }
  330. /**
  331. * <p>
  332. * Decodes all of the provided data, starting at inPos, for inAvail bytes.
  333. * Should be called at least twice: once with the data to decode, and once
  334. * with inAvail set to "-1" to alert decoder that EOF has been reached. The
  335. * "-1" call is not necessary when decoding, but it doesn't hurt, either.
  336. * </p>
  337. * <p>
  338. * Ignores all non-base64 characters. This is how chunked (e.g. 76
  339. * character) data is handled, since CR and LF are silently ignored, but has
  340. * implications for other bytes, too. This method subscribes to the
  341. * garbage-in, garbage-out philosophy: it will not check the provided data
  342. * for validity.
  343. * </p>
  344. *
  345. * @param in
  346. * byte[] array of ascii data to base64 decode.
  347. * @param inPos
  348. * Position to start reading data from.
  349. * @param inAvail
  350. * Amount of bytes available from input for encoding.
  351. * @param context
  352. * the context to be used
  353. */
  354. @Override
  355. void decode(final byte[] in, int inPos, final int inAvail, final Context context) {
  356. if (context.eof) {
  357. return;
  358. }
  359. if (inAvail < 0) {
  360. context.eof = true;
  361. }
  362. for (int i = 0; i < inAvail; i++) {
  363. final byte[] buffer = ensureBufferSize(decodeSize, context);
  364. final byte b = in[inPos++];
  365. if (b == PAD) {
  366. // We're done.
  367. context.eof = true;
  368. break;
  369. } else {
  370. if (b >= 0 && b < DECODE_TABLE.length) {
  371. final int result = DECODE_TABLE[b];
  372. if (result >= 0) {
  373. context.modulus = (context.modulus + 1) % BYTES_PER_ENCODED_BLOCK;
  374. context.ibitWorkArea = (context.ibitWorkArea << BITS_PER_ENCODED_BYTE) + result;
  375. if (context.modulus == 0) {
  376. buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 16) & MASK_8BITS);
  377. buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 8) & MASK_8BITS);
  378. buffer[context.pos++] = (byte) (context.ibitWorkArea & MASK_8BITS);
  379. }
  380. }
  381. }
  382. }
  383. }
  384. // Two forms of EOF as far as base64 decoder is concerned: actual
  385. // EOF (-1) and first time '=' character is encountered in stream.
  386. // This approach makes the '=' padding characters completely optional.
  387. if (context.eof && context.modulus != 0) {
  388. final byte[] buffer = ensureBufferSize(decodeSize, context);
  389. // We have some spare bits remaining
  390. // Output all whole multiples of 8 bits and ignore the rest
  391. switch (context.modulus) {
  392. // case 0 : // impossible, as excluded above
  393. case 1: // 6 bits - ignore entirely
  394. // TODO not currently tested; perhaps it is impossible?
  395. break;
  396. case 2: // 12 bits = 8 + 4
  397. context.ibitWorkArea = context.ibitWorkArea >> 4; // dump the
  398. // extra 4
  399. // bits
  400. buffer[context.pos++] = (byte) ((context.ibitWorkArea) & MASK_8BITS);
  401. break;
  402. case 3: // 18 bits = 8 + 8 + 2
  403. context.ibitWorkArea = context.ibitWorkArea >> 2; // dump 2 bits
  404. buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 8) & MASK_8BITS);
  405. buffer[context.pos++] = (byte) ((context.ibitWorkArea) & MASK_8BITS);
  406. break;
  407. default:
  408. throw new IllegalStateException("Impossible modulus " + context.modulus);
  409. }
  410. }
  411. }
  412. /**
  413. * Encodes binary data using the base64 algorithm but does not chunk the
  414. * output.
  415. *
  416. * @param binaryData
  417. * binary data to encode
  418. * @return byte[] containing Base64 characters in their UTF-8
  419. * representation.
  420. */
  421. public static byte[] encodeBase64(final byte[] binaryData) {
  422. return encodeBase64(binaryData, false);
  423. }
  424. /**
  425. * Encodes binary data using the base64 algorithm but does not chunk the
  426. * output.
  427. *
  428. * NOTE: We changed the behaviour of this method from multi-line chunking
  429. *
  430. * @param binaryData
  431. * binary data to encode
  432. * @return String containing Base64 characters.
  433. * @throws UnsupportedEncodingException
  434. */
  435. public static String encodeBase64String(final byte[] binaryData) throws UnsupportedEncodingException {
  436. return new String(encodeBase64(binaryData, false), "UTF-8");
  437. }
  438. /**
  439. * Encodes binary data using a URL-safe variation of the base64 algorithm
  440. * but does not chunk the output. The url-safe variation emits - and _
  441. * instead of + and / characters. <b>Note: no padding is added.</b>
  442. *
  443. * @param binaryData
  444. * binary data to encode
  445. * @return byte[] containing Base64 characters in their UTF-8
  446. * representation.
  447. */
  448. public static byte[] encodeBase64URLSafe(final byte[] binaryData) {
  449. return encodeBase64(binaryData, false, true);
  450. }
  451. /**
  452. * Encodes binary data using a URL-safe variation of the base64 algorithm
  453. * but does not chunk the output. The url-safe variation emits - and _
  454. * instead of + and / characters. <b>Note: no padding is added.</b>
  455. *
  456. * @param binaryData
  457. * binary data to encode
  458. * @return String containing Base64 characters
  459. * @throws UnsupportedEncodingException
  460. */
  461. public static String encodeBase64URLSafeString(final byte[] binaryData) throws UnsupportedEncodingException {
  462. return new String(encodeBase64(binaryData, false, true), "UTF-8");
  463. }
  464. /**
  465. * Encodes binary data using the base64 algorithm and chunks the encoded
  466. * output into 76 character blocks
  467. *
  468. * @param binaryData
  469. * binary data to encode
  470. * @return Base64 characters chunked in 76 character blocks
  471. */
  472. public static byte[] encodeBase64Chunked(final byte[] binaryData) {
  473. return encodeBase64(binaryData, true);
  474. }
  475. /**
  476. * Encodes binary data using the base64 algorithm, optionally chunking the
  477. * output into 76 character blocks.
  478. *
  479. * @param binaryData
  480. * Array containing binary data to encode.
  481. * @param isChunked
  482. * if {@code true} this encoder will chunk the base64 output into
  483. * 76 character blocks
  484. * @return Base64-encoded data.
  485. * @throws IllegalArgumentException
  486. * Thrown when the input array needs an output array bigger than
  487. * {@link Integer#MAX_VALUE}
  488. */
  489. public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked) {
  490. return encodeBase64(binaryData, isChunked, false);
  491. }
  492. /**
  493. * Encodes binary data using the base64 algorithm, optionally chunking the
  494. * output into 76 character blocks.
  495. *
  496. * @param binaryData
  497. * Array containing binary data to encode.
  498. * @param isChunked
  499. * if {@code true} this encoder will chunk the base64 output into
  500. * 76 character blocks
  501. * @param urlSafe
  502. * if {@code true} this encoder will emit - and _ instead of the
  503. * usual + and / characters. <b>Note: no padding is added when
  504. * encoding using the URL-safe alphabet.</b>
  505. * @return Base64-encoded data.
  506. * @throws IllegalArgumentException
  507. * Thrown when the input array needs an output array bigger than
  508. * {@link Integer#MAX_VALUE}
  509. */
  510. public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked, final boolean urlSafe) {
  511. return encodeBase64(binaryData, isChunked, urlSafe, Integer.MAX_VALUE);
  512. }
  513. /**
  514. * Encodes binary data using the base64 algorithm, optionally chunking the
  515. * output into 76 character blocks.
  516. *
  517. * @param binaryData
  518. * Array containing binary data to encode.
  519. * @param isChunked
  520. * if {@code true} this encoder will chunk the base64 output into
  521. * 76 character blocks
  522. * @param urlSafe
  523. * if {@code true} this encoder will emit - and _ instead of the
  524. * usual + and / characters. <b>Note: no padding is added when
  525. * encoding using the URL-safe alphabet.</b>
  526. * @param maxResultSize
  527. * The maximum result size to accept.
  528. * @return Base64-encoded data.
  529. * @throws IllegalArgumentException
  530. * Thrown when the input array needs an output array bigger than
  531. * maxResultSize
  532. */
  533. public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked, final boolean urlSafe, final int maxResultSize) {
  534. if (binaryData == null || binaryData.length == 0) {
  535. return binaryData;
  536. }
  537. // Create this so can use the super-class method
  538. // Also ensures that the same roundings are performed by the ctor and
  539. // the code
  540. final Base64 b64 = isChunked ? new Base64(urlSafe) : new Base64(0, CHUNK_SEPARATOR, urlSafe);
  541. final long len = b64.getEncodedLength(binaryData);
  542. if (len > maxResultSize) {
  543. throw new IllegalArgumentException("Input array too big, the output array would be bigger (" + len + ") than the specified maximum size of " + maxResultSize);
  544. }
  545. return b64.encode(binaryData);
  546. }
  547. /**
  548. * Decodes a Base64 String into octets
  549. *
  550. * @param base64String
  551. * String containing Base64 data
  552. * @return Array containing decoded data.
  553. * @throws UnsupportedEncodingException
  554. */
  555. public static byte[] decodeBase64(final String base64String) throws UnsupportedEncodingException {
  556. return new Base64().decode(base64String);
  557. }
  558. /**
  559. * Decodes Base64 data into octets
  560. *
  561. * @param base64Data
  562. * Byte array containing Base64 data
  563. * @return Array containing decoded data.
  564. */
  565. public static byte[] decodeBase64(final byte[] base64Data) {
  566. return new Base64().decode(base64Data);
  567. }
  568. /**
  569. * Returns whether or not the <code>octet</code> is in the Base64 alphabet.
  570. *
  571. * @param octet
  572. * The value to test
  573. * @return {@code true} if the value is defined in the the Base64 alphabet
  574. * {@code false} otherwise.
  575. */
  576. @Override
  577. protected boolean isInAlphabet(final byte octet) {
  578. return octet >= 0 && octet < decodeTable.length && decodeTable[octet] != -1;
  579. }
  580. }
  581. abstract class BaseNCodec {
  582. static class Context {
  583. /**
  584. * Place holder for the bytes we're dealing with for our based logic.
  585. * Bitwise operations store and extract the encoding or decoding from this variable.
  586. */
  587. int ibitWorkArea;
  588. /**
  589. * Place holder for the bytes we're dealing with for our based logic.
  590. * Bitwise operations store and extract the encoding or decoding from this variable.
  591. */
  592. long lbitWorkArea;
  593. /**
  594. * Buffer for streaming.
  595. */
  596. byte[] buffer;
  597. /**
  598. * Position where next character should be written in the buffer.
  599. */
  600. int pos;
  601. /**
  602. * Position where next character should be read from the buffer.
  603. */
  604. int readPos;
  605. /**
  606. * Boolean flag to indicate the EOF has been reached. Once EOF has been reached, this object becomes useless,
  607. * and must be thrown away.
  608. */
  609. boolean eof;
  610. /**
  611. * Variable tracks how many characters have been written to the current line. Only used when encoding. We use
  612. * it to make sure each encoded line never goes beyond lineLength (if lineLength > 0).
  613. */
  614. int currentLinePos;
  615. /**
  616. * Writes to the buffer only occur after every 3/5 reads when encoding, and every 4/8 reads when decoding. This
  617. * variable helps track that.
  618. */
  619. int modulus;
  620. Context() {
  621. }
  622. /**
  623. * Returns a String useful for debugging (especially within a debugger.)
  624. *
  625. * @return a String useful for debugging.
  626. */
  627. @SuppressWarnings("boxing") // OK to ignore boxing here
  628. @Override
  629. public String toString() {
  630. return String.format("%s[buffer=%s, currentLinePos=%s, eof=%s, ibitWorkArea=%s, lbitWorkArea=%s, " +
  631. "modulus=%s, pos=%s, readPos=%s]", this.getClass().getSimpleName(), Arrays.toString(buffer),
  632. currentLinePos, eof, ibitWorkArea, lbitWorkArea, modulus, pos, readPos);
  633. }
  634. }
  635. /**
  636. * EOF
  637. */
  638. static final int EOF = -1;
  639. /**
  640. * MIME chunk size per RFC 2045 section 6.8.
  641. */
  642. public static final int MIME_CHUNK_SIZE = 76;
  643. /**
  644. * PEM chunk size per RFC 1421 section 4.3.2.4.
  645. */
  646. public static final int PEM_CHUNK_SIZE = 64;
  647. private static final int DEFAULT_BUFFER_RESIZE_FACTOR = 2;
  648. /**
  649. * Defines the default buffer size - currently {@value}
  650. * - must be large enough for at least one encoded block+separator
  651. */
  652. private static final int DEFAULT_BUFFER_SIZE = 8192;
  653. /** Mask used to extract 8 bits, used in decoding bytes */
  654. protected static final int MASK_8BITS = 0xff;
  655. /**
  656. * Byte used to pad output.
  657. */
  658. protected static final byte PAD_DEFAULT = '='; // Allow static access to default
  659. protected final byte PAD = PAD_DEFAULT; // instance variable just in case it needs to vary later
  660. /** Number of bytes in each full block of unencoded data, e.g. 4 for Base64 and 5 for Base32 */
  661. private final int unencodedBlockSize;
  662. /** Number of bytes in each full block of encoded data, e.g. 3 for Base64 and 8 for Base32 */
  663. private final int encodedBlockSize;
  664. /**
  665. * Chunksize for encoding. Not used when decoding.
  666. * A value of zero or less implies no chunking of the encoded data.
  667. * Rounded down to nearest multiple of encodedBlockSize.
  668. */
  669. protected final int lineLength;
  670. /**
  671. * Size of chunk separator. Not used unless {@link #lineLength} > 0.
  672. */
  673. private final int chunkSeparatorLength;
  674. /**
  675. * Note <code>lineLength</code> is rounded down to the nearest multiple of {@link #encodedBlockSize}
  676. * If <code>chunkSeparatorLength</code> is zero, then chunking is disabled.
  677. * @param unencodedBlockSize the size of an unencoded block (e.g. Base64 = 3)
  678. * @param encodedBlockSize the size of an encoded block (e.g. Base64 = 4)
  679. * @param lineLength if &gt; 0, use chunking with a length <code>lineLength</code>
  680. * @param chunkSeparatorLength the chunk separator length, if relevant
  681. */
  682. protected BaseNCodec(final int unencodedBlockSize, final int encodedBlockSize,
  683. final int lineLength, final int chunkSeparatorLength) {
  684. this.unencodedBlockSize = unencodedBlockSize;
  685. this.encodedBlockSize = encodedBlockSize;
  686. final boolean useChunking = lineLength > 0 && chunkSeparatorLength > 0;
  687. this.lineLength = useChunking ? (lineLength / encodedBlockSize) * encodedBlockSize : 0;
  688. this.chunkSeparatorLength = chunkSeparatorLength;
  689. }
  690. /**
  691. * Returns true if this object has buffered data for reading.
  692. *
  693. * @param context the context to be used
  694. * @return true if there is data still available for reading.
  695. */
  696. boolean hasData(final Context context) { // package protected for access from I/O streams
  697. return context.buffer != null;
  698. }
  699. /**
  700. * Returns the amount of buffered data available for reading.
  701. *
  702. * @param context the context to be used
  703. * @return The amount of buffered data available for reading.
  704. */
  705. int available(final Context context) { // package protected for access from I/O streams
  706. return context.buffer != null ? context.pos - context.readPos : 0;
  707. }
  708. /**
  709. * Get the default buffer size. Can be overridden.
  710. *
  711. * @return {@link #DEFAULT_BUFFER_SIZE}
  712. */
  713. protected int getDefaultBufferSize() {
  714. return DEFAULT_BUFFER_SIZE;
  715. }
  716. /**
  717. * Increases our buffer by the {@link #DEFAULT_BUFFER_RESIZE_FACTOR}.
  718. * @param context the context to be used
  719. */
  720. private byte[] resizeBuffer(final Context context) {
  721. if (context.buffer == null) {
  722. context.buffer = new byte[getDefaultBufferSize()];
  723. context.pos = 0;
  724. context.readPos = 0;
  725. } else {
  726. final byte[] b = new byte[context.buffer.length * DEFAULT_BUFFER_RESIZE_FACTOR];
  727. System.arraycopy(context.buffer, 0, b, 0, context.buffer.length);
  728. context.buffer = b;
  729. }
  730. return context.buffer;
  731. }
  732. /**
  733. * Ensure that the buffer has room for <code>size</code> bytes
  734. *
  735. * @param size minimum spare space required
  736. * @param context the context to be used
  737. */
  738. protected byte[] ensureBufferSize(final int size, final Context context){
  739. if ((context.buffer == null) || (context.buffer.length < context.pos + size)){
  740. return resizeBuffer(context);
  741. }
  742. return context.buffer;
  743. }
  744. /**
  745. * Extracts buffered data into the provided byte[] array, starting at position bPos, up to a maximum of bAvail
  746. * bytes. Returns how many bytes were actually extracted.
  747. * <p>
  748. * Package protected for access from I/O streams.
  749. *
  750. * @param b
  751. * byte[] array to extract the buffered data into.
  752. * @param bPos
  753. * position in byte[] array to start extraction at.
  754. * @param bAvail
  755. * amount of bytes we're allowed to extract. We may extract fewer (if fewer are available).
  756. * @param context
  757. * the context to be used
  758. * @return The number of bytes successfully extracted into the provided byte[] array.
  759. */
  760. int readResults(final byte[] b, final int bPos, final int bAvail, final Context context) {
  761. if (context.buffer != null) {
  762. final int len = Math.min(available(context), bAvail);
  763. System.arraycopy(context.buffer, context.readPos, b, bPos, len);
  764. context.readPos += len;
  765. if (context.readPos >= context.pos) {
  766. context.buffer = null; // so hasData() will return false, and this method can return -1
  767. }
  768. return len;
  769. }
  770. return context.eof ? EOF : 0;
  771. }
  772. /**
  773. * Checks if a byte value is whitespace or not.
  774. * Whitespace is taken to mean: space, tab, CR, LF
  775. * @param byteToCheck
  776. * the byte to check
  777. * @return true if byte is whitespace, false otherwise
  778. */
  779. protected static boolean isWhiteSpace(final byte byteToCheck) {
  780. switch (byteToCheck) {
  781. case ' ' :
  782. case '\n' :
  783. case '\r' :
  784. case '\t' :
  785. return true;
  786. default :
  787. return false;
  788. }
  789. }
  790. /**
  791. * Encodes an Object using the Base-N algorithm. This method is provided in order to satisfy the requirements of
  792. * the Encoder interface, and will throw an EncoderException if the supplied object is not of type byte[].
  793. *
  794. * @param obj
  795. * Object to encode
  796. * @return An object (of type byte[]) containing the Base-N encoded data which corresponds to the byte[] supplied.
  797. * if the parameter supplied is not of type byte[]
  798. */
  799. public Object encode(final Object obj) throws Exception {
  800. if (!(obj instanceof byte[])) {
  801. throw new Exception("Parameter supplied to Base-N encode is not a byte[]");
  802. }
  803. return encode((byte[]) obj);
  804. }
  805. /**
  806. * Encodes a byte[] containing binary data, into a String containing characters in the Base-N alphabet.
  807. * Uses UTF8 encoding.
  808. *
  809. * @param pArray
  810. * a byte array containing binary data
  811. * @return A String containing only Base-N character data
  812. * @throws UnsupportedEncodingException
  813. */
  814. public String encodeToString(final byte[] pArray) throws UnsupportedEncodingException {
  815. return new String(encode(pArray), "UTF-8");
  816. }
  817. /**
  818. * Encodes a byte[] containing binary data, into a String containing characters in the appropriate alphabet.
  819. * Uses UTF8 encoding.
  820. *
  821. * @param pArray a byte array containing binary data
  822. * @return String containing only character data in the appropriate alphabet.
  823. * @throws UnsupportedEncodingException
  824. */
  825. public String encodeAsString(final byte[] pArray) throws UnsupportedEncodingException{
  826. return new String(encode(pArray), "UTF-8");
  827. }
  828. /**
  829. * Decodes an Object using the Base-N algorithm. This method is provided in order to satisfy the requirements of
  830. * the Decoder interface, and will throw a DecoderException if the supplied object is not of type byte[] or String.
  831. *
  832. * @param obj
  833. * Object to decode
  834. * @return An object (of type byte[]) containing the binary data which corresponds to the byte[] or String
  835. * supplied.
  836. * if the parameter supplied is not of type byte[]
  837. */
  838. public Object decode(final Object obj) throws Exception {
  839. if (obj instanceof byte[]) {
  840. return decode((byte[]) obj);
  841. } else if (obj instanceof String) {
  842. return decode((String) obj);
  843. } else {
  844. throw new Exception("Parameter supplied to Base-N decode is not a byte[] or a String");
  845. }
  846. }
  847. /**
  848. * Decodes a String containing characters in the Base-N alphabet.
  849. *
  850. * @param pArray
  851. * A String containing Base-N character data
  852. * @return a byte array containing binary data
  853. * @throws UnsupportedEncodingException
  854. */
  855. public byte[] decode(final String pArray) throws UnsupportedEncodingException {
  856. return decode(pArray.getBytes("UTF-8"));
  857. }
  858. /**
  859. * Decodes a byte[] containing characters in the Base-N alphabet.
  860. *
  861. * @param pArray
  862. * A byte array containing Base-N character data
  863. * @return a byte array containing binary data
  864. */
  865. public byte[] decode(final byte[] pArray) {
  866. if (pArray == null || pArray.length == 0) {
  867. return pArray;
  868. }
  869. final Context context = new Context();
  870. decode(pArray, 0, pArray.length, context);
  871. decode(pArray, 0, EOF, context); // Notify decoder of EOF.
  872. final byte[] result = new byte[context.pos];
  873. readResults(result, 0, result.length, context);
  874. return result;
  875. }
  876. /**
  877. * Encodes a byte[] containing binary data, into a byte[] containing characters in the alphabet.
  878. *
  879. * @param pArray
  880. * a byte array containing binary data
  881. * @return A byte array containing only the basen alphabetic character data
  882. */
  883. public byte[] encode(final byte[] pArray) {
  884. if (pArray == null || pArray.length == 0) {
  885. return pArray;
  886. }
  887. final Context context = new Context();
  888. encode(pArray, 0, pArray.length, context);
  889. encode(pArray, 0, EOF, context); // Notify encoder of EOF.
  890. final byte[] buf = new byte[context.pos - context.readPos];
  891. readResults(buf, 0, buf.length, context);
  892. return buf;
  893. }
  894. // package protected for access from I/O streams
  895. abstract void encode(byte[] pArray, int i, int length, Context context);
  896. // package protected for access from I/O streams
  897. abstract void decode(byte[] pArray, int i, int length, Context context);
  898. /**
  899. * Returns whether or not the <code>octet</code> is in the current alphabet.
  900. * Does not allow whitespace or pad.
  901. *
  902. * @param value The value to test
  903. *
  904. * @return {@code true} if the value is defined in the current alphabet, {@code false} otherwise.
  905. */
  906. protected abstract boolean isInAlphabet(byte value);
  907. /**
  908. * Tests a given byte array to see if it contains only valid characters within the alphabet.
  909. * The method optionally treats whitespace and pad as valid.
  910. *
  911. * @param arrayOctet byte array to test
  912. * @param allowWSPad if {@code true}, then whitespace and PAD are also allowed
  913. *
  914. * @return {@code true} if all bytes are valid characters in the alphabet or if the byte array is empty;
  915. * {@code false}, otherwise
  916. */
  917. public boolean isInAlphabet(final byte[] arrayOctet, final boolean allowWSPad) {
  918. for (int i = 0; i < arrayOctet.length; i++) {
  919. if (!isInAlphabet(arrayOctet[i]) &&
  920. (!allowWSPad || (arrayOctet[i] != PAD) && !isWhiteSpace(arrayOctet[i]))) {
  921. return false;
  922. }
  923. }
  924. return true;
  925. }
  926. /**
  927. * Tests a given String to see if it contains only valid characters within the alphabet.
  928. * The method treats whitespace and PAD as valid.
  929. *
  930. * @param basen String to test
  931. * @return {@code true} if all characters in the String are valid characters in the alphabet or if
  932. * the String is empty; {@code false}, otherwise
  933. * @throws UnsupportedEncodingException
  934. * @see #isInAlphabet(byte[], boolean)
  935. */
  936. public boolean isInAlphabet(final String basen) throws UnsupportedEncodingException {
  937. return isInAlphabet(basen.getBytes("UTF-8"), true);
  938. }
  939. /**
  940. * Tests a given byte array to see if it contains any characters within the alphabet or PAD.
  941. *
  942. * Intended for use in checking line-ending arrays
  943. *
  944. * @param arrayOctet
  945. * byte array to test
  946. * @return {@code true} if any byte is a valid character in the alphabet or PAD; {@code false} otherwise
  947. */
  948. protected boolean containsAlphabetOrPad(final byte[] arrayOctet) {
  949. if (arrayOctet == null) {
  950. return false;
  951. }
  952. for (final byte element : arrayOctet) {
  953. if (PAD == element || isInAlphabet(element)) {
  954. return true;
  955. }
  956. }
  957. return false;
  958. }
  959. /**
  960. * Calculates the amount of space needed to encode the supplied array.
  961. *
  962. * @param pArray byte[] array which will later be encoded
  963. *
  964. * @return amount of space needed to encoded the supplied array.
  965. * Returns a long since a max-len array will require > Integer.MAX_VALUE
  966. */
  967. public long getEncodedLength(final byte[] pArray) {
  968. // Calculate non-chunked size - rounded up to allow for padding
  969. // cast to long is needed to avoid possibility of overflow
  970. long len = ((pArray.length + unencodedBlockSize-1) / unencodedBlockSize) * (long) encodedBlockSize;
  971. if (lineLength > 0) { // We're using chunking
  972. // Round up to nearest multiple
  973. len += ((len + lineLength-1) / lineLength) * chunkSeparatorLength;
  974. }
  975. return len;
  976. }
  977. }