Base64.java 48 KB

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