Base64.java 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030
  1. /*
  2. * Copyright (C) 2004-2013 L2J Server
  3. *
  4. * This file is part of L2J Server.
  5. *
  6. * L2J Server is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * L2J Server is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. package com.l2jserver.util;
  20. import java.io.ByteArrayInputStream;
  21. import java.io.ByteArrayOutputStream;
  22. import java.io.FilterInputStream;
  23. import java.io.FilterOutputStream;
  24. import java.io.IOException;
  25. import java.io.ObjectInputStream;
  26. import java.io.ObjectOutputStream;
  27. import java.io.Serializable;
  28. import java.nio.charset.Charset;
  29. import java.nio.charset.StandardCharsets;
  30. import java.util.logging.Logger;
  31. import java.util.zip.GZIPInputStream;
  32. import java.util.zip.GZIPOutputStream;
  33. /**
  34. * Encodes and decodes to and from Base64 notation.<br>
  35. * The source is based on the work of Robert Harder.<br>
  36. * <p>
  37. * I am placing this code in the Public Domain.<br>
  38. * Do with it as you will.<br>
  39. * This software comes with no guarantees or warranties but with plenty of well-wishing instead!<br>
  40. * Please visit <a href="http://iharder.net/xmlizable">http://iharder.net/base64</a><br>
  41. * periodically to check for updates or to contribute improvements.
  42. * </p>
  43. * @author Robert Harder, rob@iharder.net
  44. * @version 2.0
  45. */
  46. public class Base64
  47. {
  48. private static final Logger _log = Logger.getLogger(Base64.class.getName());
  49. /* P U B L I C F I E L D S */
  50. /** No options specified. Value is zero. */
  51. public static final int NO_OPTIONS = 0;
  52. /** Specify encoding. */
  53. public static final int ENCODE = 1;
  54. /** Specify decoding. */
  55. public static final int DECODE = 0;
  56. /** Specify that data should be gzip-compressed. */
  57. public static final int GZIP = 2;
  58. /** Don't break lines when encoding (violates strict Base64 specification) */
  59. public static final int DONT_BREAK_LINES = 8;
  60. /* Private Fields */
  61. /** Maximum line length (76) of Base64 output. */
  62. private static final int MAX_LINE_LENGTH = 76;
  63. /** The equals sign (=) as a byte. */
  64. private static final byte EQUALS_SIGN = (byte) '=';
  65. /** The new line character (\n) as a byte. */
  66. private static final byte NEW_LINE = (byte) '\n';
  67. /** Preferred encoding. */
  68. private static final Charset PREFERRED_ENCODING = StandardCharsets.UTF_8;
  69. /** The 64 valid Base64 values. */
  70. private static final byte[] ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".getBytes(PREFERRED_ENCODING);
  71. /**
  72. * Translates a Base64 value to either its 6-bit reconstruction value or a negative number indicating some other meaning.
  73. */
  74. // @formatter:off
  75. static final byte[] DECODABET =
  76. {
  77. -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8
  78. -5, -5, // Whitespace: Tab and Linefeed
  79. -9, -9, // Decimal 11 - 12
  80. -5, // Whitespace: Carriage Return
  81. -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26
  82. -9, -9, -9, -9, -9, // Decimal 27 - 31
  83. -5, // Whitespace: Space
  84. -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42
  85. 62, // Plus sign at decimal 43
  86. -9, -9, -9, // Decimal 44 - 46
  87. 63, // Slash at decimal 47
  88. 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine
  89. -9, -9, -9, // Decimal 58 - 60
  90. -1, // Equals sign at decimal 61
  91. -9, -9, -9, // Decimal 62 - 64
  92. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N'
  93. 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z'
  94. -9, -9, -9, -9, -9, -9, // Decimal 91 - 96
  95. 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm'
  96. 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z'
  97. -9, -9, -9, -9 // Decimal 123 - 126
  98. /*
  99. * ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139
  100. * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152
  101. * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165
  102. * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178
  103. * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191
  104. * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204
  105. * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217
  106. * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230
  107. * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243
  108. * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255
  109. */
  110. };
  111. // @formatter:on
  112. // private static final byte BAD_ENCODING = -9; // Indicates error in encoding
  113. private static final byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding
  114. private static final byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding
  115. /** Defeats instantiation. */
  116. private Base64()
  117. {
  118. }
  119. /* E N C O D I N G M E T H O D S */
  120. /**
  121. * Encodes up to the first three bytes of array <var>threeBytes</var> and returns a four-byte array in Base64 notation. The actual number of significant bytes in your array is given by <var>numSigBytes</var>. The array <var>threeBytes</var> needs only be as big as <var>numSigBytes</var>. Code
  122. * can reuse a byte array by passing a four-byte array as <var>b4</var>.
  123. * @param b4 A reusable byte array to reduce array instantiation
  124. * @param threeBytes the array to convert
  125. * @param numSigBytes the number of significant bytes in your array
  126. * @return four byte array in Base64 notation.
  127. * @since 1.5.1
  128. */
  129. static byte[] encode3to4(byte[] b4, byte[] threeBytes, int numSigBytes)
  130. {
  131. encode3to4(threeBytes, 0, numSigBytes, b4, 0);
  132. return b4;
  133. }
  134. /**
  135. * Encodes up to three bytes of the array <var>source</var> and writes the resulting four Base64 bytes to <var>destination</var>.<br>
  136. * The source and destination arrays can be manipulated anywhere along their length by specifying <var>srcOffset</var> and <var>destOffset</var>.<br>
  137. * This method does not check to make sure your arrays are large enough to accommodate <var>srcOffset</var> + 3 for the <var>source</var> array or <var>destOffset</var> + 4 for the <var>destination</var> array.<br>
  138. * The actual number of significant bytes in your array is given by <var>numSigBytes</var>.
  139. * @param source the array to convert
  140. * @param srcOffset the index where conversion begins
  141. * @param numSigBytes the number of significant bytes in your array
  142. * @param destination the array to hold the conversion
  143. * @param destOffset the index where output will be put
  144. * @return the <var>destination</var> array
  145. * @since 1.3
  146. */
  147. static byte[] encode3to4(byte[] source, int srcOffset, int numSigBytes, byte[] destination, int destOffset)
  148. {
  149. // 1 2 3
  150. // 01234567890123456789012345678901 Bit position
  151. // --------000000001111111122222222 Array position from threeBytes
  152. // --------| || || || | Six bit groups to index ALPHABET
  153. // >>18 >>12 >> 6 >> 0 Right shift necessary
  154. // 0x3f 0x3f 0x3f Additional AND
  155. // Create buffer with zero-padding if there are only one or two
  156. // significant bytes passed in the array.
  157. // We have to shift left 24 in order to flush out the 1's that appear
  158. // when Java treats a value as negative that is cast from a byte to an
  159. // int.
  160. int inBuff = (numSigBytes > 0 ? ((source[srcOffset] << 24) >>> 8) : 0) | (numSigBytes > 1 ? ((source[srcOffset + 1] << 24) >>> 16) : 0) | (numSigBytes > 2 ? ((source[srcOffset + 2] << 24) >>> 24) : 0);
  161. switch (numSigBytes)
  162. {
  163. case 3:
  164. destination[destOffset] = ALPHABET[(inBuff >>> 18)];
  165. destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
  166. destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f];
  167. destination[destOffset + 3] = ALPHABET[(inBuff) & 0x3f];
  168. return destination;
  169. case 2:
  170. destination[destOffset] = ALPHABET[(inBuff >>> 18)];
  171. destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
  172. destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f];
  173. destination[destOffset + 3] = EQUALS_SIGN;
  174. return destination;
  175. case 1:
  176. destination[destOffset] = ALPHABET[(inBuff >>> 18)];
  177. destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
  178. destination[destOffset + 2] = EQUALS_SIGN;
  179. destination[destOffset + 3] = EQUALS_SIGN;
  180. return destination;
  181. default:
  182. return destination;
  183. }
  184. }
  185. /**
  186. * Serializes an object and returns the Base64-encoded version of that serialized object.<br>
  187. * If the object cannot be serialized or there is another error, the method will return <tt>null</tt>.<br>
  188. * The object is not GZip-compressed before being encoded.
  189. * @param serializableObject The object to encode
  190. * @return The Base64-encoded object
  191. * @since 1.4
  192. */
  193. public static String encodeObject(Serializable serializableObject)
  194. {
  195. return encodeObject(serializableObject, NO_OPTIONS);
  196. }
  197. /**
  198. * Serializes an object and returns the Base64-encoded version of that serialized object.<br>
  199. * If the object cannot be serialized or there is another error, the method will return <tt>null</tt>.
  200. * <p>
  201. * Valid options:
  202. *
  203. * <pre>
  204. * GZIP: gzip-compresses object before encoding it.
  205. * DONT_BREAK_LINES: don't break lines at 76 characters
  206. * &lt;i&gt;Note: Technically, this makes your encoding non-compliant.&lt;/i&gt;
  207. * </pre>
  208. * <p>
  209. * Example: <code>encodeObject( myObj, Base64.GZIP )</code> or
  210. * <p>
  211. * Example: <code>encodeObject( myObj, Base64.GZIP | Base64.DONT_BREAK_LINES )</code>
  212. * @param serializableObject The object to encode
  213. * @param options
  214. * @options Specified options
  215. * @return The Base64-encoded object
  216. * @see Base64#GZIP
  217. * @see Base64#DONT_BREAK_LINES
  218. * @since 2.0
  219. */
  220. public static String encodeObject(Serializable serializableObject, int options)
  221. {
  222. // Isolate options
  223. int gzip = (options & GZIP);
  224. int dontBreakLines = (options & DONT_BREAK_LINES);
  225. // ObjectOutputStream -> (GZIP) -> Base64 -> ByteArrayOutputStream
  226. byte[] value = null;
  227. try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
  228. Base64.OutputStream b64os = new Base64.OutputStream(baos, ENCODE | dontBreakLines);
  229. GZIPOutputStream gzipOutputStream = new GZIPOutputStream(b64os);
  230. FilterOutputStream os = (gzip == GZIP) ? gzipOutputStream : b64os;
  231. ObjectOutputStream oos = new ObjectOutputStream(os))
  232. {
  233. oos.writeObject(serializableObject);
  234. value = baos.toByteArray();
  235. }
  236. catch (IOException e)
  237. {
  238. e.printStackTrace();
  239. return null;
  240. }
  241. return value != null ? new String(value, PREFERRED_ENCODING) : null;
  242. }
  243. /**
  244. * Encodes a byte array into Base64 notation. Does not GZip-compress data.
  245. * @param source The data to convert
  246. * @return
  247. * @since 1.4
  248. */
  249. public static String encodeBytes(byte[] source)
  250. {
  251. return encodeBytes(source, 0, source.length, NO_OPTIONS);
  252. }
  253. /**
  254. * Encodes a byte array into Base64 notation.
  255. * <p>
  256. * Valid options:
  257. *
  258. * <pre>
  259. * GZIP: gzip-compresses object before encoding it.
  260. * DONT_BREAK_LINES: don't break lines at 76 characters
  261. * &lt;i&gt;Note: Technically, this makes your encoding non-compliant.&lt;/i&gt;
  262. * </pre>
  263. * <p>
  264. * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
  265. * <p>
  266. * Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DONT_BREAK_LINES )</code>
  267. * @param source The data to convert
  268. * @param options Specified options
  269. * @return
  270. * @see Base64#GZIP
  271. * @see Base64#DONT_BREAK_LINES
  272. * @since 2.0
  273. */
  274. public static String encodeBytes(byte[] source, int options)
  275. {
  276. return encodeBytes(source, 0, source.length, options);
  277. }
  278. /**
  279. * Encodes a byte array into Base64 notation. Does not GZip-compress data.
  280. * @param source The data to convert
  281. * @param off Offset in array where conversion should begin
  282. * @param len Length of data to convert
  283. * @return
  284. * @since 1.4
  285. */
  286. public static String encodeBytes(byte[] source, int off, int len)
  287. {
  288. return encodeBytes(source, off, len, NO_OPTIONS);
  289. }
  290. /**
  291. * Encodes a byte array into Base64 notation.
  292. * <p>
  293. * Valid options:
  294. *
  295. * <pre>
  296. * GZIP: gzip-compresses object before encoding it.
  297. * DONT_BREAK_LINES: don't break lines at 76 characters
  298. * &lt;i&gt;Note: Technically, this makes your encoding non-compliant.&lt;/i&gt;
  299. * </pre>
  300. * <p>
  301. * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
  302. * <p>
  303. * Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DONT_BREAK_LINES )</code>
  304. * @param source The data to convert
  305. * @param off Offset in array where conversion should begin
  306. * @param len Length of data to convert
  307. * @param options Specified options
  308. * @return
  309. * @see Base64#GZIP
  310. * @see Base64#DONT_BREAK_LINES
  311. * @since 2.0
  312. */
  313. public static String encodeBytes(byte[] source, int off, int len, int options)
  314. {
  315. // Isolate options
  316. int dontBreakLines = (options & DONT_BREAK_LINES);
  317. int gzip = (options & GZIP);
  318. // Compress?
  319. if (gzip == GZIP)
  320. {
  321. // GZip -> Base64 -> ByteArray
  322. byte[] value = null;
  323. try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
  324. Base64.OutputStream b64os = new Base64.OutputStream(baos, ENCODE | dontBreakLines);
  325. GZIPOutputStream gzos = new GZIPOutputStream(b64os))
  326. {
  327. gzos.write(source, off, len);
  328. value = baos.toByteArray();
  329. }
  330. catch (IOException e)
  331. {
  332. _log.warning("Base64: " + e.getMessage());
  333. return null;
  334. }
  335. // Return value according to relevant encoding.
  336. if (value != null)
  337. {
  338. return new String(value, PREFERRED_ENCODING);
  339. }
  340. }
  341. // Convert option to boolean in way that code likes it.
  342. boolean breakLines = dontBreakLines == 0;
  343. int len43 = (len * 4) / 3;
  344. byte[] outBuff = new byte[(len43) // Main 4:3
  345. + ((len % 3) > 0 ? 4 : 0) // Account for padding
  346. + (breakLines ? (len43 / MAX_LINE_LENGTH) : 0)]; // New lines
  347. int d = 0;
  348. int e = 0;
  349. int len2 = len - 2;
  350. int lineLength = 0;
  351. for (; d < len2; d += 3, e += 4)
  352. {
  353. encode3to4(source, d + off, 3, outBuff, e);
  354. lineLength += 4;
  355. if (breakLines && (lineLength == MAX_LINE_LENGTH))
  356. {
  357. outBuff[e + 4] = NEW_LINE;
  358. e++;
  359. lineLength = 0;
  360. }
  361. } // en dfor: each piece of array
  362. if (d < len)
  363. {
  364. encode3to4(source, d + off, len - d, outBuff, e);
  365. e += 4;
  366. }
  367. // Return value according to relevant encoding.
  368. return new String(outBuff, 0, e, PREFERRED_ENCODING);
  369. }
  370. /* D E C O D I N G M E T H O D S */
  371. /**
  372. * Decodes four bytes from array <var>source</var> and writes the resulting bytes (up to three of them) to <var>destination</var>. The source and destination arrays can be manipulated anywhere along their length by specifying <var>srcOffset</var> and <var>destOffset</var>. This method does not
  373. * check to make sure your arrays are large enough to accomodate <var>srcOffset</var> + 4 for the <var>source</var> array or <var>destOffset</var> + 3 for the <var>destination</var> array. This method returns the actual number of bytes that were converted from the Base64 encoding.
  374. * @param source the array to convert
  375. * @param srcOffset the index where conversion begins
  376. * @param destination the array to hold the conversion
  377. * @param destOffset the index where output will be put
  378. * @return the number of decoded bytes converted
  379. * @since 1.3
  380. */
  381. static int decode4to3(byte[] source, int srcOffset, byte[] destination, int destOffset)
  382. {
  383. // Example: Dk==
  384. if (source[srcOffset + 2] == EQUALS_SIGN)
  385. {
  386. // Two ways to do the same thing. Don't know which way I like best.
  387. // int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6
  388. // )
  389. // | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 );
  390. int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12);
  391. destination[destOffset] = (byte) (outBuff >>> 16);
  392. return 1;
  393. }
  394. // Example: DkL=
  395. else if (source[srcOffset + 3] == EQUALS_SIGN)
  396. {
  397. // Two ways to do the same thing. Don't know which way I like best.
  398. // int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6
  399. // )
  400. // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
  401. // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 );
  402. int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12) | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6);
  403. destination[destOffset] = (byte) (outBuff >>> 16);
  404. destination[destOffset + 1] = (byte) (outBuff >>> 8);
  405. return 2;
  406. }
  407. // Example: DkLE
  408. else
  409. {
  410. try
  411. {
  412. // Two ways to do the same thing. Don't know which way I like
  413. // best.
  414. // int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 )
  415. // >>> 6 )
  416. // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
  417. // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 )
  418. // | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 );
  419. int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12) | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6) | ((DECODABET[source[srcOffset + 3]] & 0xFF));
  420. destination[destOffset] = (byte) (outBuff >> 16);
  421. destination[destOffset + 1] = (byte) (outBuff >> 8);
  422. destination[destOffset + 2] = (byte) (outBuff);
  423. return 3;
  424. }
  425. catch (Exception e)
  426. {
  427. System.out.println(StringUtil.concat(String.valueOf(source[srcOffset]), ": ", String.valueOf(DECODABET[source[srcOffset]])));
  428. System.out.println(StringUtil.concat(String.valueOf(source[srcOffset + 1]), ": ", String.valueOf(DECODABET[source[srcOffset + 1]])));
  429. System.out.println(StringUtil.concat(String.valueOf(source[srcOffset + 2]), ": ", String.valueOf(DECODABET[source[srcOffset + 2]])));
  430. System.out.println(StringUtil.concat(String.valueOf(source[srcOffset + 3]), ": ", String.valueOf(DECODABET[source[srcOffset + 3]])));
  431. return -1;
  432. }
  433. }
  434. }
  435. /**
  436. * Very low-level access to decoding ASCII characters in the form of a byte array. Does not support automatically gunzipping or any other "fancy" features.
  437. * @param source The Base64 encoded data
  438. * @param off The offset of where to begin decoding
  439. * @param len The length of characters to decode
  440. * @return decoded data
  441. * @since 1.3
  442. */
  443. public static byte[] decode(byte[] source, int off, int len)
  444. {
  445. int len34 = (len * 3) / 4;
  446. byte[] outBuff = new byte[len34]; // Upper limit on size of output
  447. int outBuffPosn = 0;
  448. byte[] b4 = new byte[4];
  449. int b4Posn = 0;
  450. int i = 0;
  451. byte sbiCrop = 0;
  452. byte sbiDecode = 0;
  453. for (i = off; i < (off + len); i++)
  454. {
  455. sbiCrop = (byte) (source[i] & 0x7f); // Only the low seven bits
  456. sbiDecode = DECODABET[sbiCrop];
  457. if (sbiDecode >= WHITE_SPACE_ENC) // White space, Equals sign or better
  458. {
  459. if (sbiDecode >= EQUALS_SIGN_ENC)
  460. {
  461. b4[b4Posn++] = sbiCrop;
  462. if (b4Posn > 3)
  463. {
  464. outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn);
  465. b4Posn = 0;
  466. // If that was the equals sign, break out of 'for' loop
  467. if (sbiCrop == EQUALS_SIGN)
  468. {
  469. break;
  470. }
  471. } // end if: quartet built
  472. } // end if: equals sign or better
  473. } // end if: white space, equals sign or better
  474. else
  475. {
  476. System.err.println(StringUtil.concat("Bad Base64 input character at ", String.valueOf(i), ": ", String.valueOf(source[i]), "(decimal)"));
  477. return null;
  478. }
  479. }
  480. byte[] out = new byte[outBuffPosn];
  481. System.arraycopy(outBuff, 0, out, 0, outBuffPosn);
  482. return out;
  483. }
  484. /**
  485. * Decodes data from Base64 notation, automatically detecting gzip-compressed data and decompressing it.
  486. * @param s the string to decode
  487. * @return the decoded data
  488. * @since 1.4
  489. */
  490. public static byte[] decode(String s)
  491. {
  492. byte[] bytes = s.getBytes(PREFERRED_ENCODING);
  493. // Decode
  494. bytes = decode(bytes, 0, bytes.length);
  495. // Check to see if it's gzip-compressed
  496. // GZIP Magic Two-Byte Number: 0x8b1f (35615)
  497. // In case decoding returned null
  498. if ((bytes != null) && (bytes.length >= 2))
  499. {
  500. final int head = (bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00);
  501. // Don't want to get ArrayIndexOutOfBounds exception
  502. if ((bytes.length >= 4) && (GZIPInputStream.GZIP_MAGIC == head))
  503. {
  504. byte[] buffer = new byte[2048];
  505. int length = 0;
  506. try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
  507. GZIPInputStream gzis = new GZIPInputStream(bais);
  508. ByteArrayOutputStream baos = new ByteArrayOutputStream())
  509. {
  510. while ((length = gzis.read(buffer)) >= 0)
  511. {
  512. baos.write(buffer, 0, length);
  513. }
  514. // No error? Get new bytes.
  515. bytes = baos.toByteArray();
  516. }
  517. catch (IOException e)
  518. {
  519. // Just return originally-decoded bytes
  520. }
  521. }
  522. }
  523. return bytes;
  524. }
  525. /**
  526. * Attempts to decode Base64 data and deserialize a Java Object within. Returns <tt>null</tt> if there was an error.
  527. * @param encodedObject The Base64 data to decode
  528. * @return The decoded and deserialized object
  529. * @since 1.5
  530. */
  531. public static Object decodeToObject(String encodedObject)
  532. {
  533. // Decode and gunzip if necessary
  534. byte[] objBytes = decode(encodedObject);
  535. Object obj = null;
  536. try (ByteArrayInputStream bais = new ByteArrayInputStream(objBytes);
  537. ObjectInputStream ois = new ObjectInputStream(bais))
  538. {
  539. obj = ois.readObject();
  540. }
  541. catch (IOException e)
  542. {
  543. _log.warning("Base64: " + e.getMessage());
  544. }
  545. catch (ClassNotFoundException e)
  546. {
  547. _log.warning("Base64: " + e.getMessage());
  548. }
  549. return obj;
  550. }
  551. /* I N N E R C L A S S I N P U T S T R E A M */
  552. /**
  553. * A {@link #InputStream} will read data from another {@link java.io.InputStream}, given in the constructor, and encode/decode to/from Base64 notation on the fly.
  554. * @see Base64
  555. * @see java.io.FilterInputStream
  556. * @since 1.3
  557. */
  558. public static class InputStream extends FilterInputStream
  559. {
  560. // private int options; // Options specified
  561. private final boolean encode; // Encoding or decoding
  562. private int position; // Current position in the buffer
  563. private final byte[] buffer; // Small buffer holding converted data
  564. private final int bufferLength; // Length of buffer (3 or 4)
  565. private int numSigBytes; // Number of meaningful bytes in the buffer
  566. private int lineLength;
  567. private final boolean breakLines; // Break lines at less than 80 characters
  568. /**
  569. * Constructs a {@link #InputStream} in DECODE mode.
  570. * @param pIn the {@link java.io.InputStream} from which to read data.
  571. * @since 1.3
  572. */
  573. public InputStream(java.io.InputStream pIn)
  574. {
  575. this(pIn, DECODE);
  576. }
  577. /**
  578. * Constructs a {@link #InputStream} in either ENCODE or DECODE mode.
  579. * <p>
  580. * Valid options:
  581. *
  582. * <pre>
  583. * ENCODE or DECODE: Encode or Decode as data is read.
  584. * DONT_BREAK_LINES: don't break lines at 76 characters
  585. * (only meaningful when encoding)
  586. * &lt;i&gt;Note: Technically, this makes your encoding non-compliant.&lt;/i&gt;
  587. * </pre>
  588. * <p>
  589. * Example: <code>new Base64.InputStream( in, Base64.DECODE )</code>
  590. * @param pIn the {@link java.io.InputStream} from which to read data.
  591. * @param options Specified options
  592. * @see Base64#ENCODE
  593. * @see Base64#DECODE
  594. * @see Base64#DONT_BREAK_LINES
  595. * @since 2.0
  596. */
  597. public InputStream(java.io.InputStream pIn, int options)
  598. {
  599. super(pIn);
  600. // this.options = options;
  601. breakLines = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES;
  602. encode = (options & ENCODE) == ENCODE;
  603. bufferLength = encode ? 4 : 3;
  604. buffer = new byte[bufferLength];
  605. position = -1;
  606. lineLength = 0;
  607. }
  608. /**
  609. * Reads enough of the input stream to convert to/from Base64 and returns the next byte.
  610. * @return next byte
  611. * @since 1.3
  612. */
  613. @Override
  614. public int read() throws IOException
  615. {
  616. // Do we need to get data?
  617. if (position < 0)
  618. {
  619. if (encode)
  620. {
  621. byte[] b3 = new byte[3];
  622. int numBinaryBytes = 0;
  623. for (int i = 0; i < 3; i++)
  624. {
  625. try
  626. {
  627. int b = in.read();
  628. // If end of stream, b is -1.
  629. if (b >= 0)
  630. {
  631. b3[i] = (byte) b;
  632. numBinaryBytes++;
  633. }
  634. }
  635. catch (IOException e)
  636. {
  637. // Only a problem if we got no data at all.
  638. if (i == 0)
  639. {
  640. throw e;
  641. }
  642. }
  643. }
  644. if (numBinaryBytes > 0)
  645. {
  646. encode3to4(b3, 0, numBinaryBytes, buffer, 0);
  647. position = 0;
  648. numSigBytes = 4;
  649. }
  650. else
  651. {
  652. return -1;
  653. }
  654. }
  655. else
  656. {
  657. byte[] b4 = new byte[4];
  658. int i = 0;
  659. for (i = 0; i < 4; i++)
  660. {
  661. // Read four "meaningful" bytes:
  662. int b = 0;
  663. do
  664. {
  665. b = in.read();
  666. }
  667. while ((b >= 0) && (DECODABET[b & 0x7f] <= WHITE_SPACE_ENC));
  668. if (b < 0)
  669. {
  670. break; // Reads a -1 if end of stream
  671. }
  672. b4[i] = (byte) b;
  673. } // end for: each needed input byte
  674. if (i == 4)
  675. {
  676. numSigBytes = decode4to3(b4, 0, buffer, 0);
  677. position = 0;
  678. } // end if: got four characters
  679. else if (i == 0)
  680. {
  681. return -1;
  682. } // end else if: also padded correctly
  683. else
  684. {
  685. // Must have broken out from above.
  686. throw new IOException("Improperly padded Base64 input.");
  687. }
  688. }
  689. }
  690. // Got data?
  691. if (position >= 0)
  692. {
  693. // End of relevant data?
  694. if ( /* !encode && */position >= numSigBytes)
  695. {
  696. return -1;
  697. }
  698. if (encode && breakLines && (lineLength >= MAX_LINE_LENGTH))
  699. {
  700. lineLength = 0;
  701. return NEW_LINE;
  702. }
  703. // This isn't important when decoding but throwing an extra "if" seems just as wasteful.
  704. lineLength++;
  705. int b = buffer[position++];
  706. if (position >= bufferLength)
  707. {
  708. position = -1;
  709. }
  710. // This is how you "cast" a byte that's intended to be unsigned.
  711. return b & 0xFF;
  712. }
  713. // When JDK1.4 is more accepted, use an assertion here.
  714. throw new IOException("Error in Base64 code reading stream.");
  715. }
  716. /**
  717. * Calls {@link #read} repeatedly until the end of stream is reached or <var>len</var> bytes are read. Returns number of bytes read into array or -1 if end of stream is encountered.
  718. * @param dest array to hold values
  719. * @param off offset for array
  720. * @param len max number of bytes to read into array
  721. * @return bytes read into array or -1 if end of stream is encountered.
  722. * @since 1.3
  723. */
  724. @Override
  725. public int read(byte[] dest, int off, int len) throws IOException
  726. {
  727. int i;
  728. int b;
  729. for (i = 0; i < len; i++)
  730. {
  731. b = read();
  732. // if( b < 0 && i == 0 )
  733. // return -1;
  734. if (b >= 0)
  735. {
  736. dest[off + i] = (byte) b;
  737. }
  738. else if (i == 0)
  739. {
  740. return -1;
  741. }
  742. else
  743. {
  744. break;
  745. }
  746. }
  747. return i;
  748. }
  749. }
  750. /* I N N E R C L A S S O U T P U T S T R E A M */
  751. /**
  752. * A {@link #OutputStream} will write data to another {@link java.io.OutputStream}, given in the constructor, and encode/decode to/from Base64 notation on the fly.
  753. * @see Base64
  754. * @see java.io.FilterOutputStream
  755. * @since 1.3
  756. */
  757. public static class OutputStream extends FilterOutputStream
  758. {
  759. // private int options;
  760. private final boolean encode;
  761. private int position;
  762. private byte[] buffer;
  763. private final int bufferLength;
  764. private int lineLength;
  765. private final boolean breakLines;
  766. private final byte[] b4; // Scratch used in a few places
  767. private boolean suspendEncoding;
  768. /**
  769. * Constructs a {@link #OutputStream} in ENCODE mode.
  770. * @param pOut the {@link java.io.OutputStream} to which data will be written.
  771. * @since 1.3
  772. */
  773. public OutputStream(java.io.OutputStream pOut)
  774. {
  775. this(pOut, ENCODE);
  776. }
  777. /**
  778. * Constructs a {@link #OutputStream} in either ENCODE or DECODE mode.
  779. * <p>
  780. * Valid options:
  781. *
  782. * <pre>
  783. * ENCODE or DECODE: Encode or Decode as data is read.
  784. * DONT_BREAK_LINES: don't break lines at 76 characters
  785. * (only meaningful when encoding)
  786. * &lt;i&gt;Note: Technically, this makes your encoding non-compliant.&lt;/i&gt;
  787. * </pre>
  788. * <p>
  789. * Example: <code>new Base64.OutputStream( out, Base64.ENCODE )</code>
  790. * @param pOut the {@link java.io.OutputStream} to which data will be written.
  791. * @param options Specified options.
  792. * @see Base64#ENCODE
  793. * @see Base64#DECODE
  794. * @see Base64#DONT_BREAK_LINES
  795. * @since 1.3
  796. */
  797. public OutputStream(java.io.OutputStream pOut, int options)
  798. {
  799. super(pOut);
  800. // this.options = options;
  801. breakLines = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES;
  802. encode = (options & ENCODE) == ENCODE;
  803. bufferLength = encode ? 3 : 4;
  804. buffer = new byte[bufferLength];
  805. position = 0;
  806. lineLength = 0;
  807. suspendEncoding = false;
  808. b4 = new byte[4];
  809. }
  810. /**
  811. * Writes the byte to the output stream after converting to/from Base64 notation. When encoding, bytes are buffered three at a time before the output stream actually gets a write() call. When decoding, bytes are buffered four at a time.
  812. * @param theByte the byte to write
  813. * @since 1.3
  814. */
  815. @Override
  816. public void write(int theByte) throws IOException
  817. {
  818. // Encoding suspended?
  819. if (suspendEncoding)
  820. {
  821. super.out.write(theByte);
  822. return;
  823. }
  824. // Encode?
  825. if (encode)
  826. {
  827. buffer[position++] = (byte) theByte;
  828. if (position >= bufferLength) // Enough to encode.
  829. {
  830. out.write(encode3to4(b4, buffer, bufferLength));
  831. lineLength += 4;
  832. if (breakLines && (lineLength >= MAX_LINE_LENGTH))
  833. {
  834. out.write(NEW_LINE);
  835. lineLength = 0;
  836. }
  837. position = 0;
  838. }
  839. }
  840. else
  841. {
  842. // Meaningful Base64 character?
  843. if (DECODABET[theByte & 0x7f] > WHITE_SPACE_ENC)
  844. {
  845. buffer[position++] = (byte) theByte;
  846. if (position >= bufferLength) // Enough to output.
  847. {
  848. int len = Base64.decode4to3(buffer, 0, b4, 0);
  849. out.write(b4, 0, len);
  850. // out.write( Base64.decode4to3( buffer ) );
  851. position = 0;
  852. }
  853. }
  854. else if (DECODABET[theByte & 0x7f] != WHITE_SPACE_ENC)
  855. {
  856. throw new IOException("Invalid character in Base64 data.");
  857. }
  858. }
  859. }
  860. /**
  861. * Calls {@link #write} repeatedly until <var>len</var> bytes are written.
  862. * @param theBytes array from which to read bytes
  863. * @param off offset for array
  864. * @param len max number of bytes to read into array
  865. * @since 1.3
  866. */
  867. @Override
  868. public void write(byte[] theBytes, int off, int len) throws IOException
  869. {
  870. // Encoding suspended?
  871. if (suspendEncoding)
  872. {
  873. super.out.write(theBytes, off, len);
  874. return;
  875. }
  876. for (int i = 0; i < len; i++)
  877. {
  878. write(theBytes[off + i]);
  879. }
  880. }
  881. /**
  882. * Method added by PHIL. [Thanks, PHIL. -Rob] This pads the buffer without closing the stream.
  883. * @throws IOException
  884. */
  885. public void flushBase64() throws IOException
  886. {
  887. if (position > 0)
  888. {
  889. if (encode)
  890. {
  891. out.write(encode3to4(b4, buffer, position));
  892. position = 0;
  893. }
  894. else
  895. {
  896. throw new IOException("Base64 input not properly padded.");
  897. }
  898. }
  899. }
  900. /**
  901. * Flushes and closes (I think, in the superclass) the stream.
  902. * @since 1.3
  903. */
  904. @Override
  905. public void close() throws IOException
  906. {
  907. // 1. Ensure that pending characters are written
  908. flushBase64();
  909. // 2. Actually close the stream
  910. // Base class both flushes and closes.
  911. super.close();
  912. buffer = null;
  913. out = null;
  914. }
  915. /**
  916. * Suspends encoding of the stream. May be helpful if you need to embed a piece of base640-encoded data in a stream.
  917. * @throws IOException
  918. * @since 1.5.1
  919. */
  920. public void suspendEncoding() throws IOException
  921. {
  922. flushBase64();
  923. suspendEncoding = true;
  924. }
  925. /**
  926. * Resumes encoding of the stream. May be helpful if you need to embed a piece of base640-encoded data in a stream.
  927. * @since 1.5.1
  928. */
  929. public void resumeEncoding()
  930. {
  931. suspendEncoding = false;
  932. }
  933. }
  934. }