Base64.java 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390
  1. /*
  2. * This program is free software: you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation, either version 3 of the License, or (at your option) any later
  5. * version.
  6. *
  7. * This program is distributed in the hope that it will be useful, but WITHOUT
  8. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  9. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  10. * details.
  11. *
  12. * You should have received a copy of the GNU General Public License along with
  13. * this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. package com.l2jserver.util;
  16. import java.io.BufferedReader;
  17. import java.io.IOException;
  18. import java.io.InputStreamReader;
  19. import java.util.logging.Logger;
  20. /**
  21. * Encodes and decodes to and from Base64 notation.
  22. *
  23. * The source is based on the work of Robert Harder
  24. *
  25. * <p>
  26. * I am placing this code in the Public Domain. Do with it as you will. This
  27. * software comes with no guarantees or warranties but with plenty of
  28. * well-wishing instead! Please visit <a
  29. * href="http://iharder.net/xmlizable">http://iharder.net/base64</a>
  30. * periodically to check for updates or to contribute improvements.
  31. * </p>
  32. *
  33. * @author Robert Harder
  34. * @author rob@iharder.net
  35. * @version 2.0
  36. */
  37. public class Base64
  38. {
  39. private static final Logger _log = Logger.getLogger(Base64.class.getName());
  40. /* P U B L I C F I E L D S */
  41. /** No options specified. Value is zero. */
  42. public final static int NO_OPTIONS = 0;
  43. /** Specify encoding. */
  44. public final static int ENCODE = 1;
  45. /** Specify decoding. */
  46. public final static int DECODE = 0;
  47. /** Specify that data should be gzip-compressed. */
  48. public final static int GZIP = 2;
  49. /** Don't break lines when encoding (violates strict Base64 specification) */
  50. public final static int DONT_BREAK_LINES = 8;
  51. /* P R I V A T E F I E L D S */
  52. /** Maximum line length (76) of Base64 output. */
  53. private final static int MAX_LINE_LENGTH = 76;
  54. /** The equals sign (=) as a byte. */
  55. private final static byte EQUALS_SIGN = (byte) '=';
  56. /** The new line character (\n) as a byte. */
  57. private final static byte NEW_LINE = (byte) '\n';
  58. /** Preferred encoding. */
  59. private final static String PREFERRED_ENCODING = "UTF-8";
  60. /** The 64 valid Base64 values. */
  61. private final static byte[] ALPHABET;
  62. private final static byte[] _NATIVE_ALPHABET = /* May be something funny like EBCDIC */
  63. { (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G',
  64. (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N',
  65. (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U',
  66. (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) 'a', (byte) 'b',
  67. (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i',
  68. (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', (byte) 'p',
  69. (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u', (byte) 'v', (byte) 'w',
  70. (byte) 'x', (byte) 'y', (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3',
  71. (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) '+',
  72. (byte) '/' };
  73. public static void main(String[] args) throws IOException
  74. {
  75. BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
  76. System.out.print("Enter String to encode: ");
  77. final String line = bf.readLine();
  78. if (line != null)
  79. {
  80. System.out.println(Base64.encodeBytes(line.getBytes()));
  81. }
  82. }
  83. /** Determine which ALPHABET to use. */
  84. static
  85. {
  86. byte[] __bytes;
  87. try
  88. {
  89. __bytes = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".getBytes(PREFERRED_ENCODING);
  90. } // end try
  91. catch (java.io.UnsupportedEncodingException use)
  92. {
  93. __bytes = _NATIVE_ALPHABET; // Fall back to native encoding
  94. } // end catch
  95. ALPHABET = __bytes;
  96. } // end static
  97. /**
  98. * Translates a Base64 value to either its 6-bit reconstruction value or a
  99. * negative number indicating some other meaning.
  100. **/
  101. final static byte[] DECODABET = { -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8
  102. -5, -5, // Whitespace: Tab and Linefeed
  103. -9, -9, // Decimal 11 - 12
  104. -5, // Whitespace: Carriage Return
  105. -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26
  106. -9, -9, -9, -9, -9, // Decimal 27 - 31
  107. -5, // Whitespace: Space
  108. -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42
  109. 62, // Plus sign at decimal 43
  110. -9, -9, -9, // Decimal 44 - 46
  111. 63, // Slash at decimal 47
  112. 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine
  113. -9, -9, -9, // Decimal 58 - 60
  114. -1, // Equals sign at decimal 61
  115. -9, -9, -9, // Decimal 62 - 64
  116. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N'
  117. 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z'
  118. -9, -9, -9, -9, -9, -9, // Decimal 91 - 96
  119. 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm'
  120. 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z'
  121. -9, -9, -9, -9 // Decimal 123 - 126
  122. /*
  123. * ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139
  124. * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152
  125. * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165
  126. * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178
  127. * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191
  128. * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204
  129. * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217
  130. * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230
  131. * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243
  132. * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255
  133. */
  134. };
  135. // private final static byte BAD_ENCODING = -9; // Indicates error in encoding
  136. private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding
  137. private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding
  138. /** Defeats instantiation. */
  139. private Base64()
  140. {
  141. }
  142. /* E N C O D I N G M E T H O D S */
  143. // /**
  144. // * Encodes the first three bytes of array <var>threeBytes</var>
  145. // * and returns a four-byte array in Base64 notation.
  146. // *
  147. // * @param threeBytes the array to convert
  148. // * @return four byte array in Base64 notation.
  149. // * @since 1.3
  150. // */
  151. // private static byte[] encode3to4( byte[] threeBytes )
  152. // {
  153. // return encode3to4( threeBytes, 3 );
  154. // } // end encodeToBytes
  155. // /**
  156. // * Encodes up to the first three bytes of array <var>threeBytes</var>
  157. // * and returns a four-byte array in Base64 notation.
  158. // * The actual number of significant bytes in your array is
  159. // * given by <var>numSigBytes</var>.
  160. // * The array <var>threeBytes</var> needs only be as big as
  161. // * <var>numSigBytes</var>.
  162. // *
  163. // * @param threeBytes the array to convert
  164. // * @param numSigBytes the number of significant bytes in your array
  165. // * @return four byte array in Base64 notation.
  166. // * @since 1.3
  167. // */
  168. // private static byte[] encode3to4( byte[] threeBytes, int numSigBytes )
  169. // {
  170. // byte[] dest = new byte[4];
  171. // encode3to4( threeBytes, 0, numSigBytes, dest, 0 );
  172. // return dest;
  173. // }
  174. /**
  175. * Encodes up to the first three bytes of array <var>threeBytes</var> and
  176. * returns a four-byte array in Base64 notation. The actual number of
  177. * significant bytes in your array is given by <var>numSigBytes</var>. The
  178. * array <var>threeBytes</var> needs only be as big as
  179. * <var>numSigBytes</var>. Code can reuse a byte array by passing a
  180. * four-byte array as <var>b4</var>.
  181. *
  182. * @param b4
  183. * A reusable byte array to reduce array instantiation
  184. * @param threeBytes
  185. * the array to convert
  186. * @param numSigBytes
  187. * the number of significant bytes in your array
  188. * @return four byte array in Base64 notation.
  189. * @since 1.5.1
  190. */
  191. static byte[] encode3to4(byte[] b4, byte[] threeBytes, int numSigBytes)
  192. {
  193. encode3to4(threeBytes, 0, numSigBytes, b4, 0);
  194. return b4;
  195. } // end encode3to4
  196. /**
  197. * Encodes up to three bytes of the array <var>source</var> and writes the
  198. * resulting four Base64 bytes to <var>destination</var>. The source and
  199. * destination arrays can be manipulated anywhere along their length by
  200. * specifying <var>srcOffset</var> and <var>destOffset</var>. This method
  201. * does not check to make sure your arrays are large enough to accomodate
  202. * <var>srcOffset</var> + 3 for the <var>source</var> array or
  203. * <var>destOffset</var> + 4 for the <var>destination</var> array. The
  204. * actual number of significant bytes in your array is given by
  205. * <var>numSigBytes</var>.
  206. *
  207. * @param source
  208. * the array to convert
  209. * @param srcOffset
  210. * the index where conversion begins
  211. * @param numSigBytes
  212. * the number of significant bytes in your array
  213. * @param destination
  214. * the array to hold the conversion
  215. * @param destOffset
  216. * the index where output will be put
  217. * @return the <var>destination</var> array
  218. * @since 1.3
  219. */
  220. static byte[] encode3to4(byte[] source, int srcOffset, int numSigBytes, byte[] destination,
  221. int destOffset)
  222. {
  223. // 1 2 3
  224. // 01234567890123456789012345678901 Bit position
  225. // --------000000001111111122222222 Array position from threeBytes
  226. // --------| || || || | Six bit groups to index ALPHABET
  227. // >>18 >>12 >> 6 >> 0 Right shift necessary
  228. // 0x3f 0x3f 0x3f Additional AND
  229. // Create buffer with zero-padding if there are only one or two
  230. // significant bytes passed in the array.
  231. // We have to shift left 24 in order to flush out the 1's that appear
  232. // when Java treats a value as negative that is cast from a byte to an
  233. // int.
  234. int inBuff = (numSigBytes > 0 ? ((source[srcOffset] << 24) >>> 8) : 0)
  235. | (numSigBytes > 1 ? ((source[srcOffset + 1] << 24) >>> 16) : 0)
  236. | (numSigBytes > 2 ? ((source[srcOffset + 2] << 24) >>> 24) : 0);
  237. switch (numSigBytes)
  238. {
  239. case 3:
  240. destination[destOffset] = ALPHABET[(inBuff >>> 18)];
  241. destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
  242. destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f];
  243. destination[destOffset + 3] = ALPHABET[(inBuff) & 0x3f];
  244. return destination;
  245. case 2:
  246. destination[destOffset] = ALPHABET[(inBuff >>> 18)];
  247. destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
  248. destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f];
  249. destination[destOffset + 3] = EQUALS_SIGN;
  250. return destination;
  251. case 1:
  252. destination[destOffset] = ALPHABET[(inBuff >>> 18)];
  253. destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
  254. destination[destOffset + 2] = EQUALS_SIGN;
  255. destination[destOffset + 3] = EQUALS_SIGN;
  256. return destination;
  257. default:
  258. return destination;
  259. } // end switch
  260. } // end encode3to4
  261. /**
  262. * Serializes an object and returns the Base64-encoded version of that
  263. * serialized object. If the object cannot be serialized or there is another
  264. * error, the method will return <tt>null</tt>. The object is not
  265. * GZip-compressed before being encoded.
  266. *
  267. * @param serializableObject
  268. * The object to encode
  269. * @return The Base64-encoded object
  270. * @since 1.4
  271. */
  272. public static String encodeObject(java.io.Serializable serializableObject)
  273. {
  274. return encodeObject(serializableObject, NO_OPTIONS);
  275. } // end encodeObject
  276. /**
  277. * Serializes an object and returns the Base64-encoded version of that
  278. * serialized object. If the object cannot be serialized or there is another
  279. * error, the method will return <tt>null</tt>.
  280. * <p>
  281. * Valid options:
  282. *
  283. * <pre>
  284. * GZIP: gzip-compresses object before encoding it.
  285. * DONT_BREAK_LINES: don't break lines at 76 characters
  286. * &lt;i&gt;Note: Technically, this makes your encoding non-compliant.&lt;/i&gt;
  287. * </pre>
  288. * <p>
  289. * Example: <code>encodeObject( myObj, Base64.GZIP )</code> or
  290. * <p>
  291. * Example:
  292. * <code>encodeObject( myObj, Base64.GZIP | Base64.DONT_BREAK_LINES )</code>
  293. *
  294. * @param serializableObject
  295. * The object to encode
  296. * @param options
  297. * @options Specified options
  298. * @return The Base64-encoded object
  299. * @see Base64#GZIP
  300. * @see Base64#DONT_BREAK_LINES
  301. * @since 2.0
  302. */
  303. public static String encodeObject(java.io.Serializable serializableObject, int options)
  304. {
  305. // Streams
  306. java.io.ByteArrayOutputStream baos = null;
  307. java.io.OutputStream b64os = null;
  308. java.io.ObjectOutputStream oos = null;
  309. java.util.zip.GZIPOutputStream gzos = null;
  310. // Isolate options
  311. int gzip = (options & GZIP);
  312. int dontBreakLines = (options & DONT_BREAK_LINES);
  313. try
  314. {
  315. // ObjectOutputStream -> (GZIP) -> Base64 -> ByteArrayOutputStream
  316. baos = new java.io.ByteArrayOutputStream();
  317. b64os = new Base64.OutputStream(baos, ENCODE | dontBreakLines);
  318. // GZip?
  319. if (gzip == GZIP)
  320. {
  321. gzos = new java.util.zip.GZIPOutputStream(b64os);
  322. oos = new java.io.ObjectOutputStream(gzos);
  323. } // end if: gzip
  324. else
  325. oos = new java.io.ObjectOutputStream(b64os);
  326. oos.writeObject(serializableObject);
  327. } // end try
  328. catch (java.io.IOException e)
  329. {
  330. e.printStackTrace();
  331. return null;
  332. } // end catch
  333. finally
  334. {
  335. try
  336. {
  337. oos.close();
  338. }
  339. catch (Exception e)
  340. {
  341. }
  342. try
  343. {
  344. gzos.close();
  345. }
  346. catch (Exception e)
  347. {
  348. }
  349. try
  350. {
  351. b64os.close();
  352. }
  353. catch (Exception e)
  354. {
  355. }
  356. try
  357. {
  358. baos.close();
  359. }
  360. catch (Exception e)
  361. {
  362. }
  363. } // end finally
  364. // Return value according to relevant encoding.
  365. try
  366. {
  367. return new String(baos.toByteArray(), PREFERRED_ENCODING);
  368. } // end try
  369. catch (java.io.UnsupportedEncodingException uue)
  370. {
  371. return new String(baos.toByteArray());
  372. } // end catch
  373. } // end encode
  374. /**
  375. * Encodes a byte array into Base64 notation. Does not GZip-compress data.
  376. *
  377. * @param source
  378. * The data to convert
  379. * @return
  380. * @since 1.4
  381. */
  382. public static String encodeBytes(byte[] source)
  383. {
  384. return encodeBytes(source, 0, source.length, NO_OPTIONS);
  385. } // end encodeBytes
  386. /**
  387. * Encodes a byte array into Base64 notation.
  388. * <p>
  389. * Valid options:
  390. *
  391. * <pre>
  392. * GZIP: gzip-compresses object before encoding it.
  393. * DONT_BREAK_LINES: don't break lines at 76 characters
  394. * &lt;i&gt;Note: Technically, this makes your encoding non-compliant.&lt;/i&gt;
  395. * </pre>
  396. * <p>
  397. * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
  398. * <p>
  399. * Example:
  400. * <code>encodeBytes( myData, Base64.GZIP | Base64.DONT_BREAK_LINES )</code>
  401. *
  402. *
  403. * @param source
  404. * The data to convert
  405. * @param options
  406. * Specified options
  407. * @return
  408. * @see Base64#GZIP
  409. * @see Base64#DONT_BREAK_LINES
  410. * @since 2.0
  411. */
  412. public static String encodeBytes(byte[] source, int options)
  413. {
  414. return encodeBytes(source, 0, source.length, options);
  415. } // end encodeBytes
  416. /**
  417. * Encodes a byte array into Base64 notation. Does not GZip-compress data.
  418. *
  419. * @param source
  420. * The data to convert
  421. * @param off
  422. * Offset in array where conversion should begin
  423. * @param len
  424. * Length of data to convert
  425. * @return
  426. * @since 1.4
  427. */
  428. public static String encodeBytes(byte[] source, int off, int len)
  429. {
  430. return encodeBytes(source, off, len, NO_OPTIONS);
  431. } // end encodeBytes
  432. /**
  433. * Encodes a byte array into Base64 notation.
  434. * <p>
  435. * Valid options:
  436. *
  437. * <pre>
  438. * GZIP: gzip-compresses object before encoding it.
  439. * DONT_BREAK_LINES: don't break lines at 76 characters
  440. * &lt;i&gt;Note: Technically, this makes your encoding non-compliant.&lt;/i&gt;
  441. * </pre>
  442. * <p>
  443. * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
  444. * <p>
  445. * Example:
  446. * <code>encodeBytes( myData, Base64.GZIP | Base64.DONT_BREAK_LINES )</code>
  447. *
  448. *
  449. * @param source
  450. * The data to convert
  451. * @param off
  452. * Offset in array where conversion should begin
  453. * @param len
  454. * Length of data to convert
  455. * @param options
  456. * Specified options
  457. * @return
  458. * @see Base64#GZIP
  459. * @see Base64#DONT_BREAK_LINES
  460. * @since 2.0
  461. */
  462. public static String encodeBytes(byte[] source, int off, int len, int options)
  463. {
  464. // Isolate options
  465. int dontBreakLines = (options & DONT_BREAK_LINES);
  466. int gzip = (options & GZIP);
  467. // Compress?
  468. if (gzip == GZIP)
  469. {
  470. java.io.ByteArrayOutputStream baos = null;
  471. java.util.zip.GZIPOutputStream gzos = null;
  472. Base64.OutputStream b64os = null;
  473. try
  474. {
  475. // GZip -> Base64 -> ByteArray
  476. baos = new java.io.ByteArrayOutputStream();
  477. b64os = new Base64.OutputStream(baos, ENCODE | dontBreakLines);
  478. gzos = new java.util.zip.GZIPOutputStream(b64os);
  479. gzos.write(source, off, len);
  480. gzos.close();
  481. } // end try
  482. catch (java.io.IOException e)
  483. {
  484. _log.warning("Base64: " + e.getMessage());
  485. return null;
  486. } // end catch
  487. finally
  488. {
  489. try
  490. {
  491. gzos.close();
  492. }
  493. catch (Exception e)
  494. {
  495. }
  496. try
  497. {
  498. b64os.close();
  499. }
  500. catch (Exception e)
  501. {
  502. }
  503. try
  504. {
  505. baos.close();
  506. }
  507. catch (Exception e)
  508. {
  509. }
  510. } // end finally
  511. // Return value according to relevant encoding.
  512. try
  513. {
  514. return new String(baos.toByteArray(), PREFERRED_ENCODING);
  515. } // end try
  516. catch (java.io.UnsupportedEncodingException uue)
  517. {
  518. return new String(baos.toByteArray());
  519. } // end catch
  520. } // end if: compress
  521. // Convert option to boolean in way that code likes it.
  522. boolean breakLines = dontBreakLines == 0;
  523. int len43 = len * 4 / 3;
  524. byte[] outBuff = new byte[(len43) // Main 4:3
  525. + ((len % 3) > 0 ? 4 : 0) // Account for padding
  526. + (breakLines ? (len43 / MAX_LINE_LENGTH) : 0)]; // New lines
  527. int d = 0;
  528. int e = 0;
  529. int len2 = len - 2;
  530. int lineLength = 0;
  531. for (; d < len2; d += 3, e += 4)
  532. {
  533. encode3to4(source, d + off, 3, outBuff, e);
  534. lineLength += 4;
  535. if (breakLines && lineLength == MAX_LINE_LENGTH)
  536. {
  537. outBuff[e + 4] = NEW_LINE;
  538. e++;
  539. lineLength = 0;
  540. } // end if: end of line
  541. } // en dfor: each piece of array
  542. if (d < len)
  543. {
  544. encode3to4(source, d + off, len - d, outBuff, e);
  545. e += 4;
  546. } // end if: some padding needed
  547. // Return value according to relevant encoding.
  548. try
  549. {
  550. return new String(outBuff, 0, e, PREFERRED_ENCODING);
  551. } // end try
  552. catch (java.io.UnsupportedEncodingException uue)
  553. {
  554. return new String(outBuff, 0, e);
  555. } // end catch
  556. // end else: don't compress
  557. } // end encodeBytes
  558. /* D E C O D I N G M E T H O D S */
  559. // /**
  560. // * Decodes the first four bytes of array <var>fourBytes</var>
  561. // * and returns an array up to three bytes long with the
  562. // * decoded values.
  563. // *
  564. // * @param fourBytes the array with Base64 content
  565. // * @return array with decoded values
  566. // * @since 1.3
  567. // */
  568. // private static byte[] decode4to3( byte[] fourBytes )
  569. // {
  570. // byte[] outBuff1 = new byte[3];
  571. // int count = decode4to3( fourBytes, 0, outBuff1, 0 );
  572. // byte[] outBuff2 = new byte[ count ];
  573. //
  574. // for( int i = 0; i < count; i++ )
  575. // outBuff2[i] = outBuff1[i];
  576. //
  577. // return outBuff2;
  578. // }
  579. /**
  580. * Decodes four bytes from array <var>source</var> and writes the resulting
  581. * bytes (up to three of them) to <var>destination</var>. The source and
  582. * destination arrays can be manipulated anywhere along their length by
  583. * specifying <var>srcOffset</var> and <var>destOffset</var>. This method
  584. * does not check to make sure your arrays are large enough to accomodate
  585. * <var>srcOffset</var> + 4 for the <var>source</var> array or
  586. * <var>destOffset</var> + 3 for the <var>destination</var> array. This
  587. * method returns the actual number of bytes that were converted from the
  588. * Base64 encoding.
  589. *
  590. *
  591. * @param source
  592. * the array to convert
  593. * @param srcOffset
  594. * the index where conversion begins
  595. * @param destination
  596. * the array to hold the conversion
  597. * @param destOffset
  598. * the index where output will be put
  599. * @return the number of decoded bytes converted
  600. * @since 1.3
  601. */
  602. static int decode4to3(byte[] source, int srcOffset, byte[] destination, int destOffset)
  603. {
  604. // Example: Dk==
  605. if (source[srcOffset + 2] == EQUALS_SIGN)
  606. {
  607. // Two ways to do the same thing. Don't know which way I like best.
  608. // int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6
  609. // )
  610. // | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 );
  611. int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18)
  612. | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12);
  613. destination[destOffset] = (byte) (outBuff >>> 16);
  614. return 1;
  615. }
  616. // Example: DkL=
  617. else if (source[srcOffset + 3] == EQUALS_SIGN)
  618. {
  619. // Two ways to do the same thing. Don't know which way I like best.
  620. // int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6
  621. // )
  622. // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
  623. // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 );
  624. int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18)
  625. | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12)
  626. | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6);
  627. destination[destOffset] = (byte) (outBuff >>> 16);
  628. destination[destOffset + 1] = (byte) (outBuff >>> 8);
  629. return 2;
  630. }
  631. // Example: DkLE
  632. else
  633. {
  634. try
  635. {
  636. // Two ways to do the same thing. Don't know which way I like
  637. // best.
  638. // int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 )
  639. // >>> 6 )
  640. // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
  641. // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 )
  642. // | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 );
  643. int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18)
  644. | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12)
  645. | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6)
  646. | ((DECODABET[source[srcOffset + 3]] & 0xFF));
  647. destination[destOffset] = (byte) (outBuff >> 16);
  648. destination[destOffset + 1] = (byte) (outBuff >> 8);
  649. destination[destOffset + 2] = (byte) (outBuff);
  650. return 3;
  651. }
  652. catch (Exception e)
  653. {
  654. System.out.println(StringUtil.concat(String.valueOf(source[srcOffset]), ": ", String.valueOf(DECODABET[source[srcOffset]])));
  655. System.out.println(StringUtil.concat(String.valueOf(source[srcOffset + 1]), ": ", String.valueOf(DECODABET[source[srcOffset + 1]])));
  656. System.out.println(StringUtil.concat(String.valueOf(source[srcOffset + 2]), ": ", String.valueOf(DECODABET[source[srcOffset + 2]])));
  657. System.out.println(StringUtil.concat(String.valueOf(source[srcOffset + 3]), ": ", String.valueOf(DECODABET[source[srcOffset + 3]])));
  658. return -1;
  659. } // end catch
  660. }
  661. } // end decodeToBytes
  662. /**
  663. * Very low-level access to decoding ASCII characters in the form of a byte
  664. * array. Does not support automatically gunzipping or any other "fancy"
  665. * features.
  666. *
  667. * @param source
  668. * The Base64 encoded data
  669. * @param off
  670. * The offset of where to begin decoding
  671. * @param len
  672. * The length of characters to decode
  673. * @return decoded data
  674. * @since 1.3
  675. */
  676. public static byte[] decode(byte[] source, int off, int len)
  677. {
  678. int len34 = len * 3 / 4;
  679. byte[] outBuff = new byte[len34]; // Upper limit on size of output
  680. int outBuffPosn = 0;
  681. byte[] b4 = new byte[4];
  682. int b4Posn = 0;
  683. int i = 0;
  684. byte sbiCrop = 0;
  685. byte sbiDecode = 0;
  686. for (i = off; i < off + len; i++)
  687. {
  688. sbiCrop = (byte) (source[i] & 0x7f); // Only the low seven bits
  689. sbiDecode = DECODABET[sbiCrop];
  690. if (sbiDecode >= WHITE_SPACE_ENC) // White space, Equals sign or
  691. // better
  692. {
  693. if (sbiDecode >= EQUALS_SIGN_ENC)
  694. {
  695. b4[b4Posn++] = sbiCrop;
  696. if (b4Posn > 3)
  697. {
  698. outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn);
  699. b4Posn = 0;
  700. // If that was the equals sign, break out of 'for' loop
  701. if (sbiCrop == EQUALS_SIGN)
  702. break;
  703. } // end if: quartet built
  704. } // end if: equals sign or better
  705. } // end if: white space, equals sign or better
  706. else
  707. {
  708. System.err.println(StringUtil.concat("Bad Base64 input character at ", String.valueOf(i), ": ", String.valueOf(source[i]), "(decimal)"));
  709. return null;
  710. } // end else:
  711. } // each input character
  712. byte[] out = new byte[outBuffPosn];
  713. System.arraycopy(outBuff, 0, out, 0, outBuffPosn);
  714. return out;
  715. } // end decode
  716. /**
  717. * Decodes data from Base64 notation, automatically detecting
  718. * gzip-compressed data and decompressing it.
  719. *
  720. * @param s
  721. * the string to decode
  722. * @return the decoded data
  723. * @since 1.4
  724. */
  725. public static byte[] decode(String s)
  726. {
  727. byte[] bytes;
  728. try
  729. {
  730. bytes = s.getBytes(PREFERRED_ENCODING);
  731. } // end try
  732. catch (java.io.UnsupportedEncodingException uee)
  733. {
  734. bytes = s.getBytes();
  735. } // end catch
  736. // </change>
  737. // Decode
  738. bytes = decode(bytes, 0, bytes.length);
  739. // Check to see if it's gzip-compressed
  740. // GZIP Magic Two-Byte Number: 0x8b1f (35615)
  741. if (bytes != null && // In case decoding returned null
  742. bytes.length >= 2)
  743. {
  744. int head = (bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00);
  745. if (bytes.length >= 4 && // Don't want to get ArrayIndexOutOfBounds
  746. // exception
  747. java.util.zip.GZIPInputStream.GZIP_MAGIC == head)
  748. {
  749. java.io.ByteArrayInputStream bais = null;
  750. java.util.zip.GZIPInputStream gzis = null;
  751. java.io.ByteArrayOutputStream baos = null;
  752. byte[] buffer = new byte[2048];
  753. int length = 0;
  754. try
  755. {
  756. baos = new java.io.ByteArrayOutputStream();
  757. bais = new java.io.ByteArrayInputStream(bytes);
  758. gzis = new java.util.zip.GZIPInputStream(bais);
  759. while ((length = gzis.read(buffer)) >= 0)
  760. {
  761. baos.write(buffer, 0, length);
  762. } // end while: reading input
  763. // No error? Get new bytes.
  764. bytes = baos.toByteArray();
  765. } // end try
  766. catch (java.io.IOException e)
  767. {
  768. // Just return originally-decoded bytes
  769. } // end catch
  770. finally
  771. {
  772. try
  773. {
  774. baos.close();
  775. }
  776. catch (Exception e)
  777. {
  778. }
  779. try
  780. {
  781. gzis.close();
  782. }
  783. catch (Exception e)
  784. {
  785. }
  786. try
  787. {
  788. bais.close();
  789. }
  790. catch (Exception e)
  791. {
  792. }
  793. } // end finally
  794. } // end if: gzipped
  795. } // end if: bytes.length >= 2
  796. return bytes;
  797. } // end decode
  798. /**
  799. * Attempts to decode Base64 data and deserialize a Java Object within.
  800. * Returns <tt>null</tt> if there was an error.
  801. *
  802. * @param encodedObject
  803. * The Base64 data to decode
  804. * @return The decoded and deserialized object
  805. * @since 1.5
  806. */
  807. public static Object decodeToObject(String encodedObject)
  808. {
  809. // Decode and gunzip if necessary
  810. byte[] objBytes = decode(encodedObject);
  811. java.io.ByteArrayInputStream bais = null;
  812. java.io.ObjectInputStream ois = null;
  813. Object obj = null;
  814. try
  815. {
  816. bais = new java.io.ByteArrayInputStream(objBytes);
  817. ois = new java.io.ObjectInputStream(bais);
  818. obj = ois.readObject();
  819. }
  820. catch (java.io.IOException e)
  821. {
  822. _log.warning("Base64: " + e.getMessage());
  823. }
  824. catch (java.lang.ClassNotFoundException e)
  825. {
  826. _log.warning("Base64: " + e.getMessage());
  827. }
  828. finally
  829. {
  830. try
  831. {
  832. bais.close();
  833. }
  834. catch (Exception e)
  835. {
  836. }
  837. try
  838. {
  839. ois.close();
  840. }
  841. catch (Exception e)
  842. {
  843. }
  844. } // end finally
  845. return obj;
  846. } // end decodeObject
  847. /* I N N E R C L A S S I N P U T S T R E A M */
  848. /**
  849. * A {@link #InputStream} will read data from another
  850. * {@link java.io.InputStream}, given in the constructor, and encode/decode
  851. * to/from Base64 notation on the fly.
  852. *
  853. * @see Base64
  854. * @see java.io.FilterInputStream
  855. * @since 1.3
  856. */
  857. public static class InputStream extends java.io.FilterInputStream
  858. {
  859. // private int options; // Options specified
  860. private boolean encode; // Encoding or decoding
  861. private int position; // Current position in the buffer
  862. private byte[] buffer; // Small buffer holding converted data
  863. private int bufferLength; // Length of buffer (3 or 4)
  864. private int numSigBytes; // Number of meaningful bytes in the buffer
  865. private int lineLength;
  866. private boolean breakLines; // Break lines at less than 80 characters
  867. /**
  868. * Constructs a {@link #InputStream} in DECODE mode.
  869. *
  870. * @param pIn
  871. * the {@link java.io.InputStream} from which to read data.
  872. * @since 1.3
  873. */
  874. public InputStream(java.io.InputStream pIn)
  875. {
  876. this(pIn, DECODE);
  877. } // end constructor
  878. /**
  879. * Constructs a {@link #InputStream} in either ENCODE or DECODE
  880. * mode.
  881. * <p>
  882. * Valid options:
  883. *
  884. * <pre>
  885. * ENCODE or DECODE: Encode or Decode as data is read.
  886. * DONT_BREAK_LINES: don't break lines at 76 characters
  887. * (only meaningful when encoding)
  888. * &lt;i&gt;Note: Technically, this makes your encoding non-compliant.&lt;/i&gt;
  889. * </pre>
  890. * <p>
  891. * Example: <code>new Base64.InputStream( in, Base64.DECODE )</code>
  892. *
  893. *
  894. * @param pIn
  895. * the {@link java.io.InputStream} from which to read data.
  896. * @param options
  897. * Specified options
  898. * @see Base64#ENCODE
  899. * @see Base64#DECODE
  900. * @see Base64#DONT_BREAK_LINES
  901. * @since 2.0
  902. */
  903. public InputStream(java.io.InputStream pIn, int options)
  904. {
  905. super(pIn);
  906. // this.options = options;
  907. breakLines = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES;
  908. encode = (options & ENCODE) == ENCODE;
  909. bufferLength = encode ? 4 : 3;
  910. buffer = new byte[bufferLength];
  911. position = -1;
  912. lineLength = 0;
  913. } // end constructor
  914. /**
  915. * Reads enough of the input stream to convert to/from Base64 and
  916. * returns the next byte.
  917. *
  918. * @return next byte
  919. * @since 1.3
  920. */
  921. @Override
  922. public int read() throws java.io.IOException
  923. {
  924. // Do we need to get data?
  925. if (position < 0)
  926. {
  927. if (encode)
  928. {
  929. byte[] b3 = new byte[3];
  930. int numBinaryBytes = 0;
  931. for (int i = 0; i < 3; i++)
  932. {
  933. try
  934. {
  935. int b = in.read();
  936. // If end of stream, b is -1.
  937. if (b >= 0)
  938. {
  939. b3[i] = (byte) b;
  940. numBinaryBytes++;
  941. } // end if: not end of stream
  942. } // end try: read
  943. catch (java.io.IOException e)
  944. {
  945. // Only a problem if we got no data at all.
  946. if (i == 0)
  947. throw e;
  948. } // end catch
  949. } // end for: each needed input byte
  950. if (numBinaryBytes > 0)
  951. {
  952. encode3to4(b3, 0, numBinaryBytes, buffer, 0);
  953. position = 0;
  954. numSigBytes = 4;
  955. } // end if: got data
  956. else
  957. {
  958. return -1;
  959. } // end else
  960. } // end if: encoding
  961. // Else decoding
  962. else
  963. {
  964. byte[] b4 = new byte[4];
  965. int i = 0;
  966. for (i = 0; i < 4; i++)
  967. {
  968. // Read four "meaningful" bytes:
  969. int b = 0;
  970. do
  971. {
  972. b = in.read();
  973. }
  974. while (b >= 0 && DECODABET[b & 0x7f] <= WHITE_SPACE_ENC);
  975. if (b < 0)
  976. break; // Reads a -1 if end of stream
  977. b4[i] = (byte) b;
  978. } // end for: each needed input byte
  979. if (i == 4)
  980. {
  981. numSigBytes = decode4to3(b4, 0, buffer, 0);
  982. position = 0;
  983. } // end if: got four characters
  984. else if (i == 0)
  985. {
  986. return -1;
  987. } // end else if: also padded correctly
  988. else
  989. {
  990. // Must have broken out from above.
  991. throw new java.io.IOException("Improperly padded Base64 input.");
  992. } // end
  993. } // end else: decode
  994. } // end else: get data
  995. // Got data?
  996. if (position >= 0)
  997. {
  998. // End of relevant data?
  999. if ( /* !encode && */position >= numSigBytes)
  1000. return -1;
  1001. if (encode && breakLines && lineLength >= MAX_LINE_LENGTH)
  1002. {
  1003. lineLength = 0;
  1004. return '\n';
  1005. } // end if
  1006. lineLength++; // This isn't important when decoding
  1007. // but throwing an extra "if" seems
  1008. // just as wasteful.
  1009. int b = buffer[position++];
  1010. if (position >= bufferLength)
  1011. position = -1;
  1012. return b & 0xFF; // This is how you "cast" a byte that's
  1013. // intended to be unsigned.
  1014. // end else
  1015. } // end if: position >= 0
  1016. // When JDK1.4 is more accepted, use an assertion here.
  1017. throw new java.io.IOException("Error in Base64 code reading stream.");
  1018. // end else
  1019. } // end read
  1020. /**
  1021. * Calls {@link #read} repeatedly until the end of stream is reached or
  1022. * <var>len</var> bytes are read. Returns number of bytes read into
  1023. * array or -1 if end of stream is encountered.
  1024. *
  1025. * @param dest
  1026. * array to hold values
  1027. * @param off
  1028. * offset for array
  1029. * @param len
  1030. * max number of bytes to read into array
  1031. * @return bytes read into array or -1 if end of stream is encountered.
  1032. * @since 1.3
  1033. */
  1034. @Override
  1035. public int read(byte[] dest, int off, int len) throws java.io.IOException
  1036. {
  1037. int i;
  1038. int b;
  1039. for (i = 0; i < len; i++)
  1040. {
  1041. b = read();
  1042. // if( b < 0 && i == 0 )
  1043. // return -1;
  1044. if (b >= 0)
  1045. dest[off + i] = (byte) b;
  1046. else if (i == 0)
  1047. return -1;
  1048. else
  1049. break; // Out of 'for' loop
  1050. } // end for: each byte read
  1051. return i;
  1052. } // end read
  1053. } // end inner class InputStream
  1054. /* I N N E R C L A S S O U T P U T S T R E A M */
  1055. /**
  1056. * A {@link #OutputStream} will write data to another
  1057. * {@link java.io.OutputStream}, given in the constructor, and encode/decode
  1058. * to/from Base64 notation on the fly.
  1059. *
  1060. * @see Base64
  1061. * @see java.io.FilterOutputStream
  1062. * @since 1.3
  1063. */
  1064. public static class OutputStream extends java.io.FilterOutputStream
  1065. {
  1066. // private int options;
  1067. private boolean encode;
  1068. private int position;
  1069. private byte[] buffer;
  1070. private int bufferLength;
  1071. private int lineLength;
  1072. private boolean breakLines;
  1073. private byte[] b4; // Scratch used in a few places
  1074. private boolean suspendEncoding;
  1075. /**
  1076. * Constructs a {@link #OutputStream} in ENCODE mode.
  1077. *
  1078. * @param pOut
  1079. * the {@link java.io.OutputStream} to which data will be
  1080. * written.
  1081. * @since 1.3
  1082. */
  1083. public OutputStream(java.io.OutputStream pOut)
  1084. {
  1085. this(pOut, ENCODE);
  1086. } // end constructor
  1087. /**
  1088. * Constructs a {@link #OutputStream} in either ENCODE or DECODE
  1089. * mode.
  1090. * <p>
  1091. * Valid options:
  1092. *
  1093. * <pre>
  1094. * ENCODE or DECODE: Encode or Decode as data is read.
  1095. * DONT_BREAK_LINES: don't break lines at 76 characters
  1096. * (only meaningful when encoding)
  1097. * &lt;i&gt;Note: Technically, this makes your encoding non-compliant.&lt;/i&gt;
  1098. * </pre>
  1099. * <p>
  1100. * Example: <code>new Base64.OutputStream( out, Base64.ENCODE )</code>
  1101. *
  1102. * @param pOut
  1103. * the {@link java.io.OutputStream} to which data will be
  1104. * written.
  1105. * @param options
  1106. * Specified options.
  1107. * @see Base64#ENCODE
  1108. * @see Base64#DECODE
  1109. * @see Base64#DONT_BREAK_LINES
  1110. * @since 1.3
  1111. */
  1112. public OutputStream(java.io.OutputStream pOut, int options)
  1113. {
  1114. super(pOut);
  1115. // this.options = options;
  1116. breakLines = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES;
  1117. encode = (options & ENCODE) == ENCODE;
  1118. bufferLength = encode ? 3 : 4;
  1119. buffer = new byte[bufferLength];
  1120. position = 0;
  1121. lineLength = 0;
  1122. suspendEncoding = false;
  1123. b4 = new byte[4];
  1124. } // end constructor
  1125. /**
  1126. * Writes the byte to the output stream after converting to/from Base64
  1127. * notation. When encoding, bytes are buffered three at a time before
  1128. * the output stream actually gets a write() call. When decoding, bytes
  1129. * are buffered four at a time.
  1130. *
  1131. * @param theByte
  1132. * the byte to write
  1133. * @since 1.3
  1134. */
  1135. @Override
  1136. public void write(int theByte) throws java.io.IOException
  1137. {
  1138. // Encoding suspended?
  1139. if (suspendEncoding)
  1140. {
  1141. super.out.write(theByte);
  1142. return;
  1143. } // end if: supsended
  1144. // Encode?
  1145. if (encode)
  1146. {
  1147. buffer[position++] = (byte) theByte;
  1148. if (position >= bufferLength) // Enough to encode.
  1149. {
  1150. out.write(encode3to4(b4, buffer, bufferLength));
  1151. lineLength += 4;
  1152. if (breakLines && lineLength >= MAX_LINE_LENGTH)
  1153. {
  1154. out.write(NEW_LINE);
  1155. lineLength = 0;
  1156. } // end if: end of line
  1157. position = 0;
  1158. } // end if: enough to output
  1159. } // end if: encoding
  1160. // Else, Decoding
  1161. else
  1162. {
  1163. // Meaningful Base64 character?
  1164. if (DECODABET[theByte & 0x7f] > WHITE_SPACE_ENC)
  1165. {
  1166. buffer[position++] = (byte) theByte;
  1167. if (position >= bufferLength) // Enough to output.
  1168. {
  1169. int len = Base64.decode4to3(buffer, 0, b4, 0);
  1170. out.write(b4, 0, len);
  1171. // out.write( Base64.decode4to3( buffer ) );
  1172. position = 0;
  1173. } // end if: enough to output
  1174. } // end if: meaningful base64 character
  1175. else if (DECODABET[theByte & 0x7f] != WHITE_SPACE_ENC)
  1176. {
  1177. throw new java.io.IOException("Invalid character in Base64 data.");
  1178. } // end else: not white space either
  1179. } // end else: decoding
  1180. } // end write
  1181. /**
  1182. * Calls {@link #write} repeatedly until <var>len</var> bytes are
  1183. * written.
  1184. *
  1185. * @param theBytes
  1186. * array from which to read bytes
  1187. * @param off
  1188. * offset for array
  1189. * @param len
  1190. * max number of bytes to read into array
  1191. * @since 1.3
  1192. */
  1193. @Override
  1194. public void write(byte[] theBytes, int off, int len) throws java.io.IOException
  1195. {
  1196. // Encoding suspended?
  1197. if (suspendEncoding)
  1198. {
  1199. super.out.write(theBytes, off, len);
  1200. return;
  1201. } // end if: supsended
  1202. for (int i = 0; i < len; i++)
  1203. {
  1204. write(theBytes[off + i]);
  1205. } // end for: each byte written
  1206. } // end write
  1207. /**
  1208. * Method added by PHIL. [Thanks, PHIL. -Rob] This pads the buffer
  1209. * without closing the stream.
  1210. * @throws java.io.IOException
  1211. */
  1212. public void flushBase64() throws java.io.IOException
  1213. {
  1214. if (position > 0)
  1215. {
  1216. if (encode)
  1217. {
  1218. out.write(encode3to4(b4, buffer, position));
  1219. position = 0;
  1220. } // end if: encoding
  1221. else
  1222. {
  1223. throw new java.io.IOException("Base64 input not properly padded.");
  1224. } // end else: decoding
  1225. } // end if: buffer partially full
  1226. } // end flush
  1227. /**
  1228. * Flushes and closes (I think, in the superclass) the stream.
  1229. *
  1230. * @since 1.3
  1231. */
  1232. @Override
  1233. public void close() throws java.io.IOException
  1234. {
  1235. // 1. Ensure that pending characters are written
  1236. flushBase64();
  1237. // 2. Actually close the stream
  1238. // Base class both flushes and closes.
  1239. super.close();
  1240. buffer = null;
  1241. out = null;
  1242. } // end close
  1243. /**
  1244. * Suspends encoding of the stream. May be helpful if you need to embed
  1245. * a piece of base640-encoded data in a stream.
  1246. * @throws java.io.IOException
  1247. *
  1248. * @since 1.5.1
  1249. */
  1250. public void suspendEncoding() throws java.io.IOException
  1251. {
  1252. flushBase64();
  1253. suspendEncoding = true;
  1254. } // end suspendEncoding
  1255. /**
  1256. * Resumes encoding of the stream. May be helpful if you need to embed a
  1257. * piece of base640-encoded data in a stream.
  1258. *
  1259. * @since 1.5.1
  1260. */
  1261. public void resumeEncoding()
  1262. {
  1263. suspendEncoding = false;
  1264. } // end resumeEncoding
  1265. } // end inner class OutputStream
  1266. } // end class Base64