Base64.java 85 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065
  1. package org.omnimaga.omnomirc;
  2. /**
  3. * <p>Encodes and decodes to and from Base64 notation.</p>
  4. * <p>Homepage: <a href="http://iharder.net/base64">http://iharder.net/base64</a>.</p>
  5. *
  6. * <p>Example:</p>
  7. *
  8. * <code>String encoded = Base64.encode( myByteArray );</code>
  9. * <br />
  10. * <code>byte[] myByteArray = Base64.decode( encoded );</code>
  11. *
  12. * <p>The <tt>options</tt> parameter, which appears in a few places, is used to pass
  13. * several pieces of information to the encoder. In the "higher level" methods such as
  14. * encodeBytes( bytes, options ) the options parameter can be used to indicate such
  15. * things as first gzipping the bytes before encoding them, not inserting linefeeds,
  16. * and encoding using the URL-safe and Ordered dialects.</p>
  17. *
  18. * <p>Note, according to <a href="http://www.faqs.org/rfcs/rfc3548.html">RFC3548</a>,
  19. * Section 2.1, implementations should not add line feeds unless explicitly told
  20. * to do so. I've got Base64 set to this behavior now, although earlier versions
  21. * broke lines by default.</p>
  22. *
  23. * <p>The constants defined in Base64 can be OR-ed together to combine options, so you
  24. * might make a call like this:</p>
  25. *
  26. * <code>String encoded = Base64.encodeBytes( mybytes, Base64.GZIP | Base64.DO_BREAK_LINES );</code>
  27. * <p>to compress the data before encoding it and then making the output have newline characters.</p>
  28. * <p>Also...</p>
  29. * <code>String encoded = Base64.encodeBytes( crazyString.getBytes() );</code>
  30. *
  31. *
  32. *
  33. * <p>
  34. * Change Log:
  35. * </p>
  36. * <ul>
  37. * <li>v2.3.7 - Fixed subtle bug when base 64 input stream contained the
  38. * value 01111111, which is an invalid base 64 character but should not
  39. * throw an ArrayIndexOutOfBoundsException either. Led to discovery of
  40. * mishandling (or potential for better handling) of other bad input
  41. * characters. You should now get an IOException if you try decoding
  42. * something that has bad characters in it.</li>
  43. * <li>v2.3.6 - Fixed bug when breaking lines and the final byte of the encoded
  44. * string ended in the last column; the buffer was not properly shrunk and
  45. * contained an extra (null) byte that made it into the string.</li>
  46. * <li>v2.3.5 - Fixed bug in {@link #encodeFromFile} where estimated buffer size
  47. * was wrong for files of size 31, 34, and 37 bytes.</li>
  48. * <li>v2.3.4 - Fixed bug when working with gzipped streams whereby flushing
  49. * the Base64.OutputStream closed the Base64 encoding (by padding with equals
  50. * signs) too soon. Also added an option to suppress the automatic decoding
  51. * of gzipped streams. Also added experimental support for specifying a
  52. * class loader when using the
  53. * {@link #decodeToObject(java.lang.String, int, java.lang.ClassLoader)}
  54. * method.</li>
  55. * <li>v2.3.3 - Changed default char encoding to US-ASCII which reduces the internal Java
  56. * footprint with its CharEncoders and so forth. Fixed some javadocs that were
  57. * inconsistent. Removed imports and specified things like java.io.IOException
  58. * explicitly inline.</li>
  59. * <li>v2.3.2 - Reduced memory footprint! Finally refined the "guessing" of how big the
  60. * final encoded data will be so that the code doesn't have to create two output
  61. * arrays: an oversized initial one and then a final, exact-sized one. Big win
  62. * when using the {@link #encodeBytesToBytes(byte[])} family of methods (and not
  63. * using the gzip options which uses a different mechanism with streams and stuff).</li>
  64. * <li>v2.3.1 - Added {@link #encodeBytesToBytes(byte[], int, int, int)} and some
  65. * similar helper methods to be more efficient with memory by not returning a
  66. * String but just a byte array.</li>
  67. * <li>v2.3 - <strong>This is not a drop-in replacement!</strong> This is two years of comments
  68. * and bug fixes queued up and finally executed. Thanks to everyone who sent
  69. * me stuff, and I'm sorry I wasn't able to distribute your fixes to everyone else.
  70. * Much bad coding was cleaned up including throwing exceptions where necessary
  71. * instead of returning null values or something similar. Here are some changes
  72. * that may affect you:
  73. * <ul>
  74. * <li><em>Does not break lines, by default.</em> This is to keep in compliance with
  75. * <a href="http://www.faqs.org/rfcs/rfc3548.html">RFC3548</a>.</li>
  76. * <li><em>Throws exceptions instead of returning null values.</em> Because some operations
  77. * (especially those that may permit the GZIP option) use IO streams, there
  78. * is a possiblity of an java.io.IOException being thrown. After some discussion and
  79. * thought, I've changed the behavior of the methods to throw java.io.IOExceptions
  80. * rather than return null if ever there's an error. I think this is more
  81. * appropriate, though it will require some changes to your code. Sorry,
  82. * it should have been done this way to begin with.</li>
  83. * <li><em>Removed all references to System.out, System.err, and the like.</em>
  84. * Shame on me. All I can say is sorry they were ever there.</li>
  85. * <li><em>Throws NullPointerExceptions and IllegalArgumentExceptions</em> as needed
  86. * such as when passed arrays are null or offsets are invalid.</li>
  87. * <li>Cleaned up as much javadoc as I could to avoid any javadoc warnings.
  88. * This was especially annoying before for people who were thorough in their
  89. * own projects and then had gobs of javadoc warnings on this file.</li>
  90. * </ul>
  91. * <li>v2.2.1 - Fixed bug using URL_SAFE and ORDERED encodings. Fixed bug
  92. * when using very small files (~&lt; 40 bytes).</li>
  93. * <li>v2.2 - Added some helper methods for encoding/decoding directly from
  94. * one file to the next. Also added a main() method to support command line
  95. * encoding/decoding from one file to the next. Also added these Base64 dialects:
  96. * <ol>
  97. * <li>The default is RFC3548 format.</li>
  98. * <li>Calling Base64.setFormat(Base64.BASE64_FORMAT.URLSAFE_FORMAT) generates
  99. * URL and file name friendly format as described in Section 4 of RFC3548.
  100. * http://www.faqs.org/rfcs/rfc3548.html</li>
  101. * <li>Calling Base64.setFormat(Base64.BASE64_FORMAT.ORDERED_FORMAT) generates
  102. * URL and file name friendly format that preserves lexical ordering as described
  103. * in http://www.faqs.org/qa/rfcc-1940.html</li>
  104. * </ol>
  105. * Special thanks to Jim Kellerman at <a href="http://www.powerset.com/">http://www.powerset.com/</a>
  106. * for contributing the new Base64 dialects.
  107. * </li>
  108. *
  109. * <li>v2.1 - Cleaned up javadoc comments and unused variables and methods. Added
  110. * some convenience methods for reading and writing to and from files.</li>
  111. * <li>v2.0.2 - Now specifies UTF-8 encoding in places where the code fails on systems
  112. * with other encodings (like EBCDIC).</li>
  113. * <li>v2.0.1 - Fixed an error when decoding a single byte, that is, when the
  114. * encoded data was a single byte.</li>
  115. * <li>v2.0 - I got rid of methods that used booleans to set options.
  116. * Now everything is more consolidated and cleaner. The code now detects
  117. * when data that's being decoded is gzip-compressed and will decompress it
  118. * automatically. Generally things are cleaner. You'll probably have to
  119. * change some method calls that you were making to support the new
  120. * options format (<tt>int</tt>s that you "OR" together).</li>
  121. * <li>v1.5.1 - Fixed bug when decompressing and decoding to a
  122. * byte[] using <tt>decode( String s, boolean gzipCompressed )</tt>.
  123. * Added the ability to "suspend" encoding in the Output Stream so
  124. * you can turn on and off the encoding if you need to embed base64
  125. * data in an otherwise "normal" stream (like an XML file).</li>
  126. * <li>v1.5 - Output stream pases on flush() command but doesn't do anything itself.
  127. * This helps when using GZIP streams.
  128. * Added the ability to GZip-compress objects before encoding them.</li>
  129. * <li>v1.4 - Added helper methods to read/write files.</li>
  130. * <li>v1.3.6 - Fixed OutputStream.flush() so that 'position' is reset.</li>
  131. * <li>v1.3.5 - Added flag to turn on and off line breaks. Fixed bug in input stream
  132. * where last buffer being read, if not completely full, was not returned.</li>
  133. * <li>v1.3.4 - Fixed when "improperly padded stream" error was thrown at the wrong time.</li>
  134. * <li>v1.3.3 - Fixed I/O streams which were totally messed up.</li>
  135. * </ul>
  136. *
  137. * <p>
  138. * I am placing this code in the Public Domain. Do with it as you will.
  139. * This software comes with no guarantees or warranties but with
  140. * plenty of well-wishing instead!
  141. * Please visit <a href="http://iharder.net/base64">http://iharder.net/base64</a>
  142. * periodically to check for updates or to contribute improvements.
  143. * </p>
  144. *
  145. * @author Robert Harder
  146. * @author [email protected]
  147. * @version 2.3.7
  148. */
  149. public class Base64
  150. {
  151. /* ******** P U B L I C F I E L D S ******** */
  152. /** No options specified. Value is zero. */
  153. public final static int NO_OPTIONS = 0;
  154. /** Specify encoding in first bit. Value is one. */
  155. public final static int ENCODE = 1;
  156. /** Specify decoding in first bit. Value is zero. */
  157. public final static int DECODE = 0;
  158. /** Specify that data should be gzip-compressed in second bit. Value is two. */
  159. public final static int GZIP = 2;
  160. /** Specify that gzipped data should <em>not</em> be automatically gunzipped. */
  161. public final static int DONT_GUNZIP = 4;
  162. /** Do break lines when encoding. Value is 8. */
  163. public final static int DO_BREAK_LINES = 8;
  164. /**
  165. * Encode using Base64-like encoding that is URL- and Filename-safe as described
  166. * in Section 4 of RFC3548:
  167. * <a href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org/rfcs/rfc3548.html</a>.
  168. * It is important to note that data encoded this way is <em>not</em> officially valid Base64,
  169. * or at the very least should not be called Base64 without also specifying that is
  170. * was encoded using the URL- and Filename-safe dialect.
  171. */
  172. public final static int URL_SAFE = 16;
  173. /**
  174. * Encode using the special "ordered" dialect of Base64 described here:
  175. * <a href="http://www.faqs.org/qa/rfcc-1940.html">http://www.faqs.org/qa/rfcc-1940.html</a>.
  176. */
  177. public final static int ORDERED = 32;
  178. /* ******** P R I V A T E F I E L D S ******** */
  179. /** Maximum line length (76) of Base64 output. */
  180. private final static int MAX_LINE_LENGTH = 76;
  181. /** The equals sign (=) as a byte. */
  182. private final static byte EQUALS_SIGN = (byte)'=';
  183. /** The new line character (\n) as a byte. */
  184. private final static byte NEW_LINE = (byte)'\n';
  185. /** Preferred encoding. */
  186. private final static String PREFERRED_ENCODING = "US-ASCII";
  187. private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding
  188. private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding
  189. /* ******** S T A N D A R D B A S E 6 4 A L P H A B E T ******** */
  190. /** The 64 valid Base64 values. */
  191. /* Host platform me be something funny like EBCDIC, so we hardcode these values. */
  192. private final static byte[] _STANDARD_ALPHABET = {
  193. (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
  194. (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
  195. (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
  196. (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
  197. (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
  198. (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
  199. (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
  200. (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z',
  201. (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5',
  202. (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'+', (byte)'/'
  203. };
  204. /**
  205. * Translates a Base64 value to either its 6-bit reconstruction value
  206. * or a negative number indicating some other meaning.
  207. **/
  208. private final static byte[] _STANDARD_DECODABET = {
  209. -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8
  210. -5,-5, // Whitespace: Tab and Linefeed
  211. -9,-9, // Decimal 11 - 12
  212. -5, // Whitespace: Carriage Return
  213. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26
  214. -9,-9,-9,-9,-9, // Decimal 27 - 31
  215. -5, // Whitespace: Space
  216. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42
  217. 62, // Plus sign at decimal 43
  218. -9,-9,-9, // Decimal 44 - 46
  219. 63, // Slash at decimal 47
  220. 52,53,54,55,56,57,58,59,60,61, // Numbers zero through nine
  221. -9,-9,-9, // Decimal 58 - 60
  222. -1, // Equals sign at decimal 61
  223. -9,-9,-9, // Decimal 62 - 64
  224. 0,1,2,3,4,5,6,7,8,9,10,11,12,13, // Letters 'A' through 'N'
  225. 14,15,16,17,18,19,20,21,22,23,24,25, // Letters 'O' through 'Z'
  226. -9,-9,-9,-9,-9,-9, // Decimal 91 - 96
  227. 26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm'
  228. 39,40,41,42,43,44,45,46,47,48,49,50,51, // Letters 'n' through 'z'
  229. -9,-9,-9,-9,-9 // Decimal 123 - 127
  230. ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139
  231. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152
  232. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165
  233. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178
  234. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191
  235. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204
  236. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217
  237. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230
  238. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243
  239. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255
  240. };
  241. /* ******** U R L S A F E B A S E 6 4 A L P H A B E T ******** */
  242. /**
  243. * Used in the URL- and Filename-safe dialect described in Section 4 of RFC3548:
  244. * <a href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org/rfcs/rfc3548.html</a>.
  245. * Notice that the last two bytes become "hyphen" and "underscore" instead of "plus" and "slash."
  246. */
  247. private final static byte[] _URL_SAFE_ALPHABET = {
  248. (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
  249. (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
  250. (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
  251. (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
  252. (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
  253. (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
  254. (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
  255. (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z',
  256. (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5',
  257. (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'-', (byte)'_'
  258. };
  259. /**
  260. * Used in decoding URL- and Filename-safe dialects of Base64.
  261. */
  262. private final static byte[] _URL_SAFE_DECODABET = {
  263. -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8
  264. -5,-5, // Whitespace: Tab and Linefeed
  265. -9,-9, // Decimal 11 - 12
  266. -5, // Whitespace: Carriage Return
  267. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26
  268. -9,-9,-9,-9,-9, // Decimal 27 - 31
  269. -5, // Whitespace: Space
  270. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42
  271. -9, // Plus sign at decimal 43
  272. -9, // Decimal 44
  273. 62, // Minus sign at decimal 45
  274. -9, // Decimal 46
  275. -9, // Slash at decimal 47
  276. 52,53,54,55,56,57,58,59,60,61, // Numbers zero through nine
  277. -9,-9,-9, // Decimal 58 - 60
  278. -1, // Equals sign at decimal 61
  279. -9,-9,-9, // Decimal 62 - 64
  280. 0,1,2,3,4,5,6,7,8,9,10,11,12,13, // Letters 'A' through 'N'
  281. 14,15,16,17,18,19,20,21,22,23,24,25, // Letters 'O' through 'Z'
  282. -9,-9,-9,-9, // Decimal 91 - 94
  283. 63, // Underscore at decimal 95
  284. -9, // Decimal 96
  285. 26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm'
  286. 39,40,41,42,43,44,45,46,47,48,49,50,51, // Letters 'n' through 'z'
  287. -9,-9,-9,-9,-9 // Decimal 123 - 127
  288. ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139
  289. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152
  290. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165
  291. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178
  292. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191
  293. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204
  294. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217
  295. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230
  296. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243
  297. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255
  298. };
  299. /* ******** O R D E R E D B A S E 6 4 A L P H A B E T ******** */
  300. /**
  301. * I don't get the point of this technique, but someone requested it,
  302. * and it is described here:
  303. * <a href="http://www.faqs.org/qa/rfcc-1940.html">http://www.faqs.org/qa/rfcc-1940.html</a>.
  304. */
  305. private final static byte[] _ORDERED_ALPHABET = {
  306. (byte)'-',
  307. (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4',
  308. (byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9',
  309. (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
  310. (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
  311. (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
  312. (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
  313. (byte)'_',
  314. (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
  315. (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
  316. (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
  317. (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z'
  318. };
  319. /**
  320. * Used in decoding the "ordered" dialect of Base64.
  321. */
  322. private final static byte[] _ORDERED_DECODABET = {
  323. -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8
  324. -5,-5, // Whitespace: Tab and Linefeed
  325. -9,-9, // Decimal 11 - 12
  326. -5, // Whitespace: Carriage Return
  327. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26
  328. -9,-9,-9,-9,-9, // Decimal 27 - 31
  329. -5, // Whitespace: Space
  330. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42
  331. -9, // Plus sign at decimal 43
  332. -9, // Decimal 44
  333. 0, // Minus sign at decimal 45
  334. -9, // Decimal 46
  335. -9, // Slash at decimal 47
  336. 1,2,3,4,5,6,7,8,9,10, // Numbers zero through nine
  337. -9,-9,-9, // Decimal 58 - 60
  338. -1, // Equals sign at decimal 61
  339. -9,-9,-9, // Decimal 62 - 64
  340. 11,12,13,14,15,16,17,18,19,20,21,22,23, // Letters 'A' through 'M'
  341. 24,25,26,27,28,29,30,31,32,33,34,35,36, // Letters 'N' through 'Z'
  342. -9,-9,-9,-9, // Decimal 91 - 94
  343. 37, // Underscore at decimal 95
  344. -9, // Decimal 96
  345. 38,39,40,41,42,43,44,45,46,47,48,49,50, // Letters 'a' through 'm'
  346. 51,52,53,54,55,56,57,58,59,60,61,62,63, // Letters 'n' through 'z'
  347. -9,-9,-9,-9,-9 // Decimal 123 - 127
  348. ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139
  349. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152
  350. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165
  351. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178
  352. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191
  353. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204
  354. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217
  355. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230
  356. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243
  357. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255
  358. };
  359. /* ******** D E T E R M I N E W H I C H A L H A B E T ******** */
  360. /**
  361. * Returns one of the _SOMETHING_ALPHABET byte arrays depending on
  362. * the options specified.
  363. * It's possible, though silly, to specify ORDERED <b>and</b> URLSAFE
  364. * in which case one of them will be picked, though there is
  365. * no guarantee as to which one will be picked.
  366. */
  367. private final static byte[] getAlphabet( int options ) {
  368. if ((options & URL_SAFE) == URL_SAFE) {
  369. return _URL_SAFE_ALPHABET;
  370. } else if ((options & ORDERED) == ORDERED) {
  371. return _ORDERED_ALPHABET;
  372. } else {
  373. return _STANDARD_ALPHABET;
  374. }
  375. } // end getAlphabet
  376. /**
  377. * Returns one of the _SOMETHING_DECODABET byte arrays depending on
  378. * the options specified.
  379. * It's possible, though silly, to specify ORDERED and URL_SAFE
  380. * in which case one of them will be picked, though there is
  381. * no guarantee as to which one will be picked.
  382. */
  383. private final static byte[] getDecodabet( int options ) {
  384. if( (options & URL_SAFE) == URL_SAFE) {
  385. return _URL_SAFE_DECODABET;
  386. } else if ((options & ORDERED) == ORDERED) {
  387. return _ORDERED_DECODABET;
  388. } else {
  389. return _STANDARD_DECODABET;
  390. }
  391. } // end getAlphabet
  392. /** Defeats instantiation. */
  393. private Base64(){}
  394. /* ******** E N C O D I N G M E T H O D S ******** */
  395. /**
  396. * Encodes up to the first three bytes of array <var>threeBytes</var>
  397. * and returns a four-byte array in Base64 notation.
  398. * The actual number of significant bytes in your array is
  399. * given by <var>numSigBytes</var>.
  400. * The array <var>threeBytes</var> needs only be as big as
  401. * <var>numSigBytes</var>.
  402. * Code can reuse a byte array by passing a four-byte array as <var>b4</var>.
  403. *
  404. * @param b4 A reusable byte array to reduce array instantiation
  405. * @param threeBytes the array to convert
  406. * @param numSigBytes the number of significant bytes in your array
  407. * @return four byte array in Base64 notation.
  408. * @since 1.5.1
  409. */
  410. private static byte[] encode3to4( byte[] b4, byte[] threeBytes, int numSigBytes, int options ) {
  411. encode3to4( threeBytes, 0, numSigBytes, b4, 0, options );
  412. return b4;
  413. } // end encode3to4
  414. /**
  415. * <p>Encodes up to three bytes of the array <var>source</var>
  416. * and writes the resulting four Base64 bytes to <var>destination</var>.
  417. * The source and destination arrays can be manipulated
  418. * anywhere along their length by specifying
  419. * <var>srcOffset</var> and <var>destOffset</var>.
  420. * This method does not check to make sure your arrays
  421. * are large enough to accomodate <var>srcOffset</var> + 3 for
  422. * the <var>source</var> array or <var>destOffset</var> + 4 for
  423. * the <var>destination</var> array.
  424. * The actual number of significant bytes in your array is
  425. * given by <var>numSigBytes</var>.</p>
  426. * <p>This is the lowest level of the encoding methods with
  427. * all possible parameters.</p>
  428. *
  429. * @param source the array to convert
  430. * @param srcOffset the index where conversion begins
  431. * @param numSigBytes the number of significant bytes in your array
  432. * @param destination the array to hold the conversion
  433. * @param destOffset the index where output will be put
  434. * @return the <var>destination</var> array
  435. * @since 1.3
  436. */
  437. private static byte[] encode3to4(
  438. byte[] source, int srcOffset, int numSigBytes,
  439. byte[] destination, int destOffset, int options ) {
  440. byte[] ALPHABET = getAlphabet( options );
  441. // 1 2 3
  442. // 01234567890123456789012345678901 Bit position
  443. // --------000000001111111122222222 Array position from threeBytes
  444. // --------| || || || | Six bit groups to index ALPHABET
  445. // >>18 >>12 >> 6 >> 0 Right shift necessary
  446. // 0x3f 0x3f 0x3f Additional AND
  447. // Create buffer with zero-padding if there are only one or two
  448. // significant bytes passed in the array.
  449. // We have to shift left 24 in order to flush out the 1's that appear
  450. // when Java treats a value as negative that is cast from a byte to an int.
  451. int inBuff = ( numSigBytes > 0 ? ((source[ srcOffset ] << 24) >>> 8) : 0 )
  452. | ( numSigBytes > 1 ? ((source[ srcOffset + 1 ] << 24) >>> 16) : 0 )
  453. | ( numSigBytes > 2 ? ((source[ srcOffset + 2 ] << 24) >>> 24) : 0 );
  454. switch( numSigBytes )
  455. {
  456. case 3:
  457. destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ];
  458. destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
  459. destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ];
  460. destination[ destOffset + 3 ] = ALPHABET[ (inBuff ) & 0x3f ];
  461. return destination;
  462. case 2:
  463. destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ];
  464. destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
  465. destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ];
  466. destination[ destOffset + 3 ] = EQUALS_SIGN;
  467. return destination;
  468. case 1:
  469. destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ];
  470. destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
  471. destination[ destOffset + 2 ] = EQUALS_SIGN;
  472. destination[ destOffset + 3 ] = EQUALS_SIGN;
  473. return destination;
  474. default:
  475. return destination;
  476. } // end switch
  477. } // end encode3to4
  478. /**
  479. * Performs Base64 encoding on the <code>raw</code> ByteBuffer,
  480. * writing it to the <code>encoded</code> ByteBuffer.
  481. * This is an experimental feature. Currently it does not
  482. * pass along any options (such as {@link #DO_BREAK_LINES}
  483. * or {@link #GZIP}.
  484. *
  485. * @param raw input buffer
  486. * @param encoded output buffer
  487. * @since 2.3
  488. */
  489. public static void encode( java.nio.ByteBuffer raw, java.nio.ByteBuffer encoded ){
  490. byte[] raw3 = new byte[3];
  491. byte[] enc4 = new byte[4];
  492. while( raw.hasRemaining() ){
  493. int rem = Math.min(3,raw.remaining());
  494. raw.get(raw3,0,rem);
  495. Base64.encode3to4(enc4, raw3, rem, Base64.NO_OPTIONS );
  496. encoded.put(enc4);
  497. } // end input remaining
  498. }
  499. /**
  500. * Performs Base64 encoding on the <code>raw</code> ByteBuffer,
  501. * writing it to the <code>encoded</code> CharBuffer.
  502. * This is an experimental feature. Currently it does not
  503. * pass along any options (such as {@link #DO_BREAK_LINES}
  504. * or {@link #GZIP}.
  505. *
  506. * @param raw input buffer
  507. * @param encoded output buffer
  508. * @since 2.3
  509. */
  510. public static void encode( java.nio.ByteBuffer raw, java.nio.CharBuffer encoded ){
  511. byte[] raw3 = new byte[3];
  512. byte[] enc4 = new byte[4];
  513. while( raw.hasRemaining() ){
  514. int rem = Math.min(3,raw.remaining());
  515. raw.get(raw3,0,rem);
  516. Base64.encode3to4(enc4, raw3, rem, Base64.NO_OPTIONS );
  517. for( int i = 0; i < 4; i++ ){
  518. encoded.put( (char)(enc4[i] & 0xFF) );
  519. }
  520. } // end input remaining
  521. }
  522. /**
  523. * Serializes an object and returns the Base64-encoded
  524. * version of that serialized object.
  525. *
  526. * <p>As of v 2.3, if the object
  527. * cannot be serialized or there is another error,
  528. * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
  529. * In earlier versions, it just returned a null value, but
  530. * in retrospect that's a pretty poor way to handle it.</p>
  531. *
  532. * The object is not GZip-compressed before being encoded.
  533. *
  534. * @param serializableObject The object to encode
  535. * @return The Base64-encoded object
  536. * @throws java.io.IOException if there is an error
  537. * @throws NullPointerException if serializedObject is null
  538. * @since 1.4
  539. */
  540. public static String encodeObject( java.io.Serializable serializableObject )
  541. throws java.io.IOException {
  542. return encodeObject( serializableObject, NO_OPTIONS );
  543. } // end encodeObject
  544. /**
  545. * Serializes an object and returns the Base64-encoded
  546. * version of that serialized object.
  547. *
  548. * <p>As of v 2.3, if the object
  549. * cannot be serialized or there is another error,
  550. * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
  551. * In earlier versions, it just returned a null value, but
  552. * in retrospect that's a pretty poor way to handle it.</p>
  553. *
  554. * The object is not GZip-compressed before being encoded.
  555. * <p>
  556. * Example options:<pre>
  557. * GZIP: gzip-compresses object before encoding it.
  558. * DO_BREAK_LINES: break lines at 76 characters
  559. * </pre>
  560. * <p>
  561. * Example: <code>encodeObject( myObj, Base64.GZIP )</code> or
  562. * <p>
  563. * Example: <code>encodeObject( myObj, Base64.GZIP | Base64.DO_BREAK_LINES )</code>
  564. *
  565. * @param serializableObject The object to encode
  566. * @param options Specified options
  567. * @return The Base64-encoded object
  568. * @see Base64#GZIP
  569. * @see Base64#DO_BREAK_LINES
  570. * @throws java.io.IOException if there is an error
  571. * @since 2.0
  572. */
  573. public static String encodeObject( java.io.Serializable serializableObject, int options )
  574. throws java.io.IOException {
  575. if( serializableObject == null ){
  576. throw new NullPointerException( "Cannot serialize a null object." );
  577. } // end if: null
  578. // Streams
  579. java.io.ByteArrayOutputStream baos = null;
  580. java.io.OutputStream b64os = null;
  581. java.util.zip.GZIPOutputStream gzos = null;
  582. java.io.ObjectOutputStream oos = null;
  583. try {
  584. // ObjectOutputStream -> (GZIP) -> Base64 -> ByteArrayOutputStream
  585. baos = new java.io.ByteArrayOutputStream();
  586. b64os = new Base64.OutputStream( baos, ENCODE | options );
  587. if( (options & GZIP) != 0 ){
  588. // Gzip
  589. gzos = new java.util.zip.GZIPOutputStream(b64os);
  590. oos = new java.io.ObjectOutputStream( gzos );
  591. } else {
  592. // Not gzipped
  593. oos = new java.io.ObjectOutputStream( b64os );
  594. }
  595. oos.writeObject( serializableObject );
  596. } // end try
  597. catch( java.io.IOException e ) {
  598. // Catch it and then throw it immediately so that
  599. // the finally{} block is called for cleanup.
  600. throw e;
  601. } // end catch
  602. finally {
  603. try{ oos.close(); } catch( Exception e ){}
  604. try{ gzos.close(); } catch( Exception e ){}
  605. try{ b64os.close(); } catch( Exception e ){}
  606. try{ baos.close(); } catch( Exception e ){}
  607. } // end finally
  608. // Return value according to relevant encoding.
  609. try {
  610. return new String( baos.toByteArray(), PREFERRED_ENCODING );
  611. } // end try
  612. catch (java.io.UnsupportedEncodingException uue){
  613. // Fall back to some Java default
  614. return new String( baos.toByteArray() );
  615. } // end catch
  616. } // end encode
  617. /**
  618. * Encodes a byte array into Base64 notation.
  619. * Does not GZip-compress data.
  620. *
  621. * @param source The data to convert
  622. * @return The data in Base64-encoded form
  623. * @throws NullPointerException if source array is null
  624. * @since 1.4
  625. */
  626. public static String encodeBytes( byte[] source ) {
  627. // Since we're not going to have the GZIP encoding turned on,
  628. // we're not going to have an java.io.IOException thrown, so
  629. // we should not force the user to have to catch it.
  630. String encoded = null;
  631. try {
  632. encoded = encodeBytes(source, 0, source.length, NO_OPTIONS);
  633. } catch (java.io.IOException ex) {
  634. assert false : ex.getMessage();
  635. } // end catch
  636. assert encoded != null;
  637. return encoded;
  638. } // end encodeBytes
  639. /**
  640. * Encodes a byte array into Base64 notation.
  641. * <p>
  642. * Example options:<pre>
  643. * GZIP: gzip-compresses object before encoding it.
  644. * DO_BREAK_LINES: break lines at 76 characters
  645. * <i>Note: Technically, this makes your encoding non-compliant.</i>
  646. * </pre>
  647. * <p>
  648. * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
  649. * <p>
  650. * Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DO_BREAK_LINES )</code>
  651. *
  652. *
  653. * <p>As of v 2.3, if there is an error with the GZIP stream,
  654. * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
  655. * In earlier versions, it just returned a null value, but
  656. * in retrospect that's a pretty poor way to handle it.</p>
  657. *
  658. *
  659. * @param source The data to convert
  660. * @param options Specified options
  661. * @return The Base64-encoded data as a String
  662. * @see Base64#GZIP
  663. * @see Base64#DO_BREAK_LINES
  664. * @throws java.io.IOException if there is an error
  665. * @throws NullPointerException if source array is null
  666. * @since 2.0
  667. */
  668. public static String encodeBytes( byte[] source, int options ) throws java.io.IOException {
  669. return encodeBytes( source, 0, source.length, options );
  670. } // end encodeBytes
  671. /**
  672. * Encodes a byte array into Base64 notation.
  673. * Does not GZip-compress data.
  674. *
  675. * <p>As of v 2.3, if there is an error,
  676. * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
  677. * In earlier versions, it just returned a null value, but
  678. * in retrospect that's a pretty poor way to handle it.</p>
  679. *
  680. *
  681. * @param source The data to convert
  682. * @param off Offset in array where conversion should begin
  683. * @param len Length of data to convert
  684. * @return The Base64-encoded data as a String
  685. * @throws NullPointerException if source array is null
  686. * @throws IllegalArgumentException if source array, offset, or length are invalid
  687. * @since 1.4
  688. */
  689. public static String encodeBytes( byte[] source, int off, int len ) {
  690. // Since we're not going to have the GZIP encoding turned on,
  691. // we're not going to have an java.io.IOException thrown, so
  692. // we should not force the user to have to catch it.
  693. String encoded = null;
  694. try {
  695. encoded = encodeBytes( source, off, len, NO_OPTIONS );
  696. } catch (java.io.IOException ex) {
  697. assert false : ex.getMessage();
  698. } // end catch
  699. assert encoded != null;
  700. return encoded;
  701. } // end encodeBytes
  702. /**
  703. * Encodes a byte array into Base64 notation.
  704. * <p>
  705. * Example options:<pre>
  706. * GZIP: gzip-compresses object before encoding it.
  707. * DO_BREAK_LINES: break lines at 76 characters
  708. * <i>Note: Technically, this makes your encoding non-compliant.</i>
  709. * </pre>
  710. * <p>
  711. * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
  712. * <p>
  713. * Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DO_BREAK_LINES )</code>
  714. *
  715. *
  716. * <p>As of v 2.3, if there is an error with the GZIP stream,
  717. * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
  718. * In earlier versions, it just returned a null value, but
  719. * in retrospect that's a pretty poor way to handle it.</p>
  720. *
  721. *
  722. * @param source The data to convert
  723. * @param off Offset in array where conversion should begin
  724. * @param len Length of data to convert
  725. * @param options Specified options
  726. * @return The Base64-encoded data as a String
  727. * @see Base64#GZIP
  728. * @see Base64#DO_BREAK_LINES
  729. * @throws java.io.IOException if there is an error
  730. * @throws NullPointerException if source array is null
  731. * @throws IllegalArgumentException if source array, offset, or length are invalid
  732. * @since 2.0
  733. */
  734. public static String encodeBytes( byte[] source, int off, int len, int options ) throws java.io.IOException {
  735. byte[] encoded = encodeBytesToBytes( source, off, len, options );
  736. // Return value according to relevant encoding.
  737. try {
  738. return new String( encoded, PREFERRED_ENCODING );
  739. } // end try
  740. catch (java.io.UnsupportedEncodingException uue) {
  741. return new String( encoded );
  742. } // end catch
  743. } // end encodeBytes
  744. /**
  745. * Similar to {@link #encodeBytes(byte[])} but returns
  746. * a byte array instead of instantiating a String. This is more efficient
  747. * if you're working with I/O streams and have large data sets to encode.
  748. *
  749. *
  750. * @param source The data to convert
  751. * @return The Base64-encoded data as a byte[] (of ASCII characters)
  752. * @throws NullPointerException if source array is null
  753. * @since 2.3.1
  754. */
  755. public static byte[] encodeBytesToBytes( byte[] source ) {
  756. byte[] encoded = null;
  757. try {
  758. encoded = encodeBytesToBytes( source, 0, source.length, Base64.NO_OPTIONS );
  759. } catch( java.io.IOException ex ) {
  760. assert false : "IOExceptions only come from GZipping, which is turned off: " + ex.getMessage();
  761. }
  762. return encoded;
  763. }
  764. /**
  765. * Similar to {@link #encodeBytes(byte[], int, int, int)} but returns
  766. * a byte array instead of instantiating a String. This is more efficient
  767. * if you're working with I/O streams and have large data sets to encode.
  768. *
  769. *
  770. * @param source The data to convert
  771. * @param off Offset in array where conversion should begin
  772. * @param len Length of data to convert
  773. * @param options Specified options
  774. * @return The Base64-encoded data as a String
  775. * @see Base64#GZIP
  776. * @see Base64#DO_BREAK_LINES
  777. * @throws java.io.IOException if there is an error
  778. * @throws NullPointerException if source array is null
  779. * @throws IllegalArgumentException if source array, offset, or length are invalid
  780. * @since 2.3.1
  781. */
  782. public static byte[] encodeBytesToBytes( byte[] source, int off, int len, int options ) throws java.io.IOException {
  783. if( source == null ){
  784. throw new NullPointerException( "Cannot serialize a null array." );
  785. } // end if: null
  786. if( off < 0 ){
  787. throw new IllegalArgumentException( "Cannot have negative offset: " + off );
  788. } // end if: off < 0
  789. if( len < 0 ){
  790. throw new IllegalArgumentException( "Cannot have length offset: " + len );
  791. } // end if: len < 0
  792. if( off + len > source.length ){
  793. throw new IllegalArgumentException(
  794. String.format( "Cannot have offset of %d and length of %d with array of length %d", off,len,source.length));
  795. } // end if: off < 0
  796. // Compress?
  797. if( (options & GZIP) != 0 ) {
  798. java.io.ByteArrayOutputStream baos = null;
  799. java.util.zip.GZIPOutputStream gzos = null;
  800. Base64.OutputStream b64os = null;
  801. try {
  802. // GZip -> Base64 -> ByteArray
  803. baos = new java.io.ByteArrayOutputStream();
  804. b64os = new Base64.OutputStream( baos, ENCODE | options );
  805. gzos = new java.util.zip.GZIPOutputStream( b64os );
  806. gzos.write( source, off, len );
  807. gzos.close();
  808. } // end try
  809. catch( java.io.IOException e ) {
  810. // Catch it and then throw it immediately so that
  811. // the finally{} block is called for cleanup.
  812. throw e;
  813. } // end catch
  814. finally {
  815. try{ gzos.close(); } catch( Exception e ){}
  816. try{ b64os.close(); } catch( Exception e ){}
  817. try{ baos.close(); } catch( Exception e ){}
  818. } // end finally
  819. return baos.toByteArray();
  820. } // end if: compress
  821. // Else, don't compress. Better not to use streams at all then.
  822. else {
  823. boolean breakLines = (options & DO_BREAK_LINES) != 0;
  824. //int len43 = len * 4 / 3;
  825. //byte[] outBuff = new byte[ ( len43 ) // Main 4:3
  826. // + ( (len % 3) > 0 ? 4 : 0 ) // Account for padding
  827. // + (breakLines ? ( len43 / MAX_LINE_LENGTH ) : 0) ]; // New lines
  828. // Try to determine more precisely how big the array needs to be.
  829. // If we get it right, we don't have to do an array copy, and
  830. // we save a bunch of memory.
  831. int encLen = ( len / 3 ) * 4 + ( len % 3 > 0 ? 4 : 0 ); // Bytes needed for actual encoding
  832. if( breakLines ){
  833. encLen += encLen / MAX_LINE_LENGTH; // Plus extra newline characters
  834. }
  835. byte[] outBuff = new byte[ encLen ];
  836. int d = 0;
  837. int e = 0;
  838. int len2 = len - 2;
  839. int lineLength = 0;
  840. for( ; d < len2; d+=3, e+=4 ) {
  841. encode3to4( source, d+off, 3, outBuff, e, options );
  842. lineLength += 4;
  843. if( breakLines && lineLength >= MAX_LINE_LENGTH )
  844. {
  845. outBuff[e+4] = NEW_LINE;
  846. e++;
  847. lineLength = 0;
  848. } // end if: end of line
  849. } // en dfor: each piece of array
  850. if( d < len ) {
  851. encode3to4( source, d+off, len - d, outBuff, e, options );
  852. e += 4;
  853. } // end if: some padding needed
  854. // Only resize array if we didn't guess it right.
  855. if( e <= outBuff.length - 1 ){
  856. // If breaking lines and the last byte falls right at
  857. // the line length (76 bytes per line), there will be
  858. // one extra byte, and the array will need to be resized.
  859. // Not too bad of an estimate on array size, I'd say.
  860. byte[] finalOut = new byte[e];
  861. System.arraycopy(outBuff,0, finalOut,0,e);
  862. //System.err.println("Having to resize array from " + outBuff.length + " to " + e );
  863. return finalOut;
  864. } else {
  865. //System.err.println("No need to resize array.");
  866. return outBuff;
  867. }
  868. } // end else: don't compress
  869. } // end encodeBytesToBytes
  870. /* ******** D E C O D I N G M E T H O D S ******** */
  871. /**
  872. * Decodes four bytes from array <var>source</var>
  873. * and writes the resulting bytes (up to three of them)
  874. * to <var>destination</var>.
  875. * The source and destination arrays can be manipulated
  876. * anywhere along their length by specifying
  877. * <var>srcOffset</var> and <var>destOffset</var>.
  878. * This method does not check to make sure your arrays
  879. * are large enough to accomodate <var>srcOffset</var> + 4 for
  880. * the <var>source</var> array or <var>destOffset</var> + 3 for
  881. * the <var>destination</var> array.
  882. * This method returns the actual number of bytes that
  883. * were converted from the Base64 encoding.
  884. * <p>This is the lowest level of the decoding methods with
  885. * all possible parameters.</p>
  886. *
  887. *
  888. * @param source the array to convert
  889. * @param srcOffset the index where conversion begins
  890. * @param destination the array to hold the conversion
  891. * @param destOffset the index where output will be put
  892. * @param options alphabet type is pulled from this (standard, url-safe, ordered)
  893. * @return the number of decoded bytes converted
  894. * @throws NullPointerException if source or destination arrays are null
  895. * @throws IllegalArgumentException if srcOffset or destOffset are invalid
  896. * or there is not enough room in the array.
  897. * @since 1.3
  898. */
  899. private static int decode4to3(
  900. byte[] source, int srcOffset,
  901. byte[] destination, int destOffset, int options ) {
  902. // Lots of error checking and exception throwing
  903. if( source == null ){
  904. throw new NullPointerException( "Source array was null." );
  905. } // end if
  906. if( destination == null ){
  907. throw new NullPointerException( "Destination array was null." );
  908. } // end if
  909. if( srcOffset < 0 || srcOffset + 3 >= source.length ){
  910. throw new IllegalArgumentException( String.format(
  911. "Source array with length %d cannot have offset of %d and still process four bytes.", source.length, srcOffset ) );
  912. } // end if
  913. if( destOffset < 0 || destOffset +2 >= destination.length ){
  914. throw new IllegalArgumentException( String.format(
  915. "Destination array with length %d cannot have offset of %d and still store three bytes.", destination.length, destOffset ) );
  916. } // end if
  917. byte[] DECODABET = getDecodabet( options );
  918. // Example: Dk==
  919. if( source[ srcOffset + 2] == EQUALS_SIGN ) {
  920. // Two ways to do the same thing. Don't know which way I like best.
  921. //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 )
  922. // | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 );
  923. int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 )
  924. | ( ( DECODABET[ source[ srcOffset + 1] ] & 0xFF ) << 12 );
  925. destination[ destOffset ] = (byte)( outBuff >>> 16 );
  926. return 1;
  927. }
  928. // Example: DkL=
  929. else if( source[ srcOffset + 3 ] == EQUALS_SIGN ) {
  930. // Two ways to do the same thing. Don't know which way I like best.
  931. //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 )
  932. // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
  933. // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 );
  934. int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 )
  935. | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 )
  936. | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6 );
  937. destination[ destOffset ] = (byte)( outBuff >>> 16 );
  938. destination[ destOffset + 1 ] = (byte)( outBuff >>> 8 );
  939. return 2;
  940. }
  941. // Example: DkLE
  942. else {
  943. // Two ways to do the same thing. Don't know which way I like best.
  944. //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 )
  945. // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
  946. // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 )
  947. // | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 );
  948. int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 )
  949. | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 )
  950. | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6)
  951. | ( ( DECODABET[ source[ srcOffset + 3 ] ] & 0xFF ) );
  952. destination[ destOffset ] = (byte)( outBuff >> 16 );
  953. destination[ destOffset + 1 ] = (byte)( outBuff >> 8 );
  954. destination[ destOffset + 2 ] = (byte)( outBuff );
  955. return 3;
  956. }
  957. } // end decodeToBytes
  958. /**
  959. * Low-level access to decoding ASCII characters in
  960. * the form of a byte array. <strong>Ignores GUNZIP option, if
  961. * it's set.</strong> This is not generally a recommended method,
  962. * although it is used internally as part of the decoding process.
  963. * Special case: if len = 0, an empty array is returned. Still,
  964. * if you need more speed and reduced memory footprint (and aren't
  965. * gzipping), consider this method.
  966. *
  967. * @param source The Base64 encoded data
  968. * @return decoded data
  969. * @since 2.3.1
  970. */
  971. public static byte[] decode( byte[] source )
  972. throws java.io.IOException {
  973. byte[] decoded = null;
  974. // try {
  975. decoded = decode( source, 0, source.length, Base64.NO_OPTIONS );
  976. // } catch( java.io.IOException ex ) {
  977. // assert false : "IOExceptions only come from GZipping, which is turned off: " + ex.getMessage();
  978. // }
  979. return decoded;
  980. }
  981. /**
  982. * Low-level access to decoding ASCII characters in
  983. * the form of a byte array. <strong>Ignores GUNZIP option, if
  984. * it's set.</strong> This is not generally a recommended method,
  985. * although it is used internally as part of the decoding process.
  986. * Special case: if len = 0, an empty array is returned. Still,
  987. * if you need more speed and reduced memory footprint (and aren't
  988. * gzipping), consider this method.
  989. *
  990. * @param source The Base64 encoded data
  991. * @param off The offset of where to begin decoding
  992. * @param len The length of characters to decode
  993. * @param options Can specify options such as alphabet type to use
  994. * @return decoded data
  995. * @throws java.io.IOException If bogus characters exist in source data
  996. * @since 1.3
  997. */
  998. public static byte[] decode( byte[] source, int off, int len, int options )
  999. throws java.io.IOException {
  1000. // Lots of error checking and exception throwing
  1001. if( source == null ){
  1002. throw new NullPointerException( "Cannot decode null source array." );
  1003. } // end if
  1004. if( off < 0 || off + len > source.length ){
  1005. throw new IllegalArgumentException( String.format(
  1006. "Source array with length %d cannot have offset of %d and process %d bytes.", source.length, off, len ) );
  1007. } // end if
  1008. if( len == 0 ){
  1009. return new byte[0];
  1010. }else if( len < 4 ){
  1011. throw new IllegalArgumentException(
  1012. "Base64-encoded string must have at least four characters, but length specified was " + len );
  1013. } // end if
  1014. byte[] DECODABET = getDecodabet( options );
  1015. int len34 = len * 3 / 4; // Estimate on array size
  1016. byte[] outBuff = new byte[ len34 ]; // Upper limit on size of output
  1017. int outBuffPosn = 0; // Keep track of where we're writing
  1018. byte[] b4 = new byte[4]; // Four byte buffer from source, eliminating white space
  1019. int b4Posn = 0; // Keep track of four byte input buffer
  1020. int i = 0; // Source array counter
  1021. byte sbiDecode = 0; // Special value from DECODABET
  1022. for( i = off; i < off+len; i++ ) { // Loop through source
  1023. sbiDecode = DECODABET[ source[i]&0xFF ];
  1024. // White space, Equals sign, or legit Base64 character
  1025. // Note the values such as -5 and -9 in the
  1026. // DECODABETs at the top of the file.
  1027. if( sbiDecode >= WHITE_SPACE_ENC ) {
  1028. if( sbiDecode >= EQUALS_SIGN_ENC ) {
  1029. b4[ b4Posn++ ] = source[i]; // Save non-whitespace
  1030. if( b4Posn > 3 ) { // Time to decode?
  1031. outBuffPosn += decode4to3( b4, 0, outBuff, outBuffPosn, options );
  1032. b4Posn = 0;
  1033. // If that was the equals sign, break out of 'for' loop
  1034. if( source[i] == EQUALS_SIGN ) {
  1035. break;
  1036. } // end if: equals sign
  1037. } // end if: quartet built
  1038. } // end if: equals sign or better
  1039. } // end if: white space, equals sign or better
  1040. else {
  1041. // There's a bad input character in the Base64 stream.
  1042. throw new java.io.IOException( String.format(
  1043. "Bad Base64 input character decimal %d in array position %d", ((int)source[i])&0xFF, i ) );
  1044. } // end else:
  1045. } // each input character
  1046. byte[] out = new byte[ outBuffPosn ];
  1047. System.arraycopy( outBuff, 0, out, 0, outBuffPosn );
  1048. return out;
  1049. } // end decode
  1050. /**
  1051. * Decodes data from Base64 notation, automatically
  1052. * detecting gzip-compressed data and decompressing it.
  1053. *
  1054. * @param s the string to decode
  1055. * @return the decoded data
  1056. * @throws java.io.IOException If there is a problem
  1057. * @since 1.4
  1058. */
  1059. public static byte[] decode( String s ) throws java.io.IOException {
  1060. return decode( s, NO_OPTIONS );
  1061. }
  1062. /**
  1063. * Decodes data from Base64 notation, automatically
  1064. * detecting gzip-compressed data and decompressing it.
  1065. *
  1066. * @param s the string to decode
  1067. * @param options encode options such as URL_SAFE
  1068. * @return the decoded data
  1069. * @throws java.io.IOException if there is an error
  1070. * @throws NullPointerException if <tt>s</tt> is null
  1071. * @since 1.4
  1072. */
  1073. public static byte[] decode( String s, int options ) throws java.io.IOException {
  1074. if( s == null ){
  1075. throw new NullPointerException( "Input string was null." );
  1076. } // end if
  1077. byte[] bytes;
  1078. try {
  1079. bytes = s.getBytes( PREFERRED_ENCODING );
  1080. } // end try
  1081. catch( java.io.UnsupportedEncodingException uee ) {
  1082. bytes = s.getBytes();
  1083. } // end catch
  1084. //</change>
  1085. // Decode
  1086. bytes = decode( bytes, 0, bytes.length, options );
  1087. // Check to see if it's gzip-compressed
  1088. // GZIP Magic Two-Byte Number: 0x8b1f (35615)
  1089. boolean dontGunzip = (options & DONT_GUNZIP) != 0;
  1090. if( (bytes != null) && (bytes.length >= 4) && (!dontGunzip) ) {
  1091. int head = ((int)bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00);
  1092. if( java.util.zip.GZIPInputStream.GZIP_MAGIC == head ) {
  1093. java.io.ByteArrayInputStream bais = null;
  1094. java.util.zip.GZIPInputStream gzis = null;
  1095. java.io.ByteArrayOutputStream baos = null;
  1096. byte[] buffer = new byte[2048];
  1097. int length = 0;
  1098. try {
  1099. baos = new java.io.ByteArrayOutputStream();
  1100. bais = new java.io.ByteArrayInputStream( bytes );
  1101. gzis = new java.util.zip.GZIPInputStream( bais );
  1102. while( ( length = gzis.read( buffer ) ) >= 0 ) {
  1103. baos.write(buffer,0,length);
  1104. } // end while: reading input
  1105. // No error? Get new bytes.
  1106. bytes = baos.toByteArray();
  1107. } // end try
  1108. catch( java.io.IOException e ) {
  1109. e.printStackTrace();
  1110. // Just return originally-decoded bytes
  1111. } // end catch
  1112. finally {
  1113. try{ baos.close(); } catch( Exception e ){}
  1114. try{ gzis.close(); } catch( Exception e ){}
  1115. try{ bais.close(); } catch( Exception e ){}
  1116. } // end finally
  1117. } // end if: gzipped
  1118. } // end if: bytes.length >= 2
  1119. return bytes;
  1120. } // end decode
  1121. /**
  1122. * Attempts to decode Base64 data and deserialize a Java
  1123. * Object within. Returns <tt>null</tt> if there was an error.
  1124. *
  1125. * @param encodedObject The Base64 data to decode
  1126. * @return The decoded and deserialized object
  1127. * @throws NullPointerException if encodedObject is null
  1128. * @throws java.io.IOException if there is a general error
  1129. * @throws ClassNotFoundException if the decoded object is of a
  1130. * class that cannot be found by the JVM
  1131. * @since 1.5
  1132. */
  1133. public static Object decodeToObject( String encodedObject )
  1134. throws java.io.IOException, java.lang.ClassNotFoundException {
  1135. return decodeToObject(encodedObject,NO_OPTIONS,null);
  1136. }
  1137. /**
  1138. * Attempts to decode Base64 data and deserialize a Java
  1139. * Object within. Returns <tt>null</tt> if there was an error.
  1140. * If <tt>loader</tt> is not null, it will be the class loader
  1141. * used when deserializing.
  1142. *
  1143. * @param encodedObject The Base64 data to decode
  1144. * @param options Various parameters related to decoding
  1145. * @param loader Optional class loader to use in deserializing classes.
  1146. * @return The decoded and deserialized object
  1147. * @throws NullPointerException if encodedObject is null
  1148. * @throws java.io.IOException if there is a general error
  1149. * @throws ClassNotFoundException if the decoded object is of a
  1150. * class that cannot be found by the JVM
  1151. * @since 2.3.4
  1152. */
  1153. public static Object decodeToObject(
  1154. String encodedObject, int options, final ClassLoader loader )
  1155. throws java.io.IOException, java.lang.ClassNotFoundException {
  1156. // Decode and gunzip if necessary
  1157. byte[] objBytes = decode( encodedObject, options );
  1158. java.io.ByteArrayInputStream bais = null;
  1159. java.io.ObjectInputStream ois = null;
  1160. Object obj = null;
  1161. try {
  1162. bais = new java.io.ByteArrayInputStream( objBytes );
  1163. // If no custom class loader is provided, use Java's builtin OIS.
  1164. if( loader == null ){
  1165. ois = new java.io.ObjectInputStream( bais );
  1166. } // end if: no loader provided
  1167. // Else make a customized object input stream that uses
  1168. // the provided class loader.
  1169. else {
  1170. ois = new java.io.ObjectInputStream(bais){
  1171. @Override
  1172. public Class<?> resolveClass(java.io.ObjectStreamClass streamClass)
  1173. throws java.io.IOException, ClassNotFoundException {
  1174. Class c = Class.forName(streamClass.getName(), false, loader);
  1175. if( c == null ){
  1176. return super.resolveClass(streamClass);
  1177. } else {
  1178. return c; // Class loader knows of this class.
  1179. } // end else: not null
  1180. } // end resolveClass
  1181. }; // end ois
  1182. } // end else: no custom class loader
  1183. obj = ois.readObject();
  1184. } // end try
  1185. catch( java.io.IOException e ) {
  1186. throw e; // Catch and throw in order to execute finally{}
  1187. } // end catch
  1188. catch( java.lang.ClassNotFoundException e ) {
  1189. throw e; // Catch and throw in order to execute finally{}
  1190. } // end catch
  1191. finally {
  1192. try{ bais.close(); } catch( Exception e ){}
  1193. try{ ois.close(); } catch( Exception e ){}
  1194. } // end finally
  1195. return obj;
  1196. } // end decodeObject
  1197. /**
  1198. * Convenience method for encoding data to a file.
  1199. *
  1200. * <p>As of v 2.3, if there is a error,
  1201. * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
  1202. * In earlier versions, it just returned false, but
  1203. * in retrospect that's a pretty poor way to handle it.</p>
  1204. *
  1205. * @param dataToEncode byte array of data to encode in base64 form
  1206. * @param filename Filename for saving encoded data
  1207. * @throws java.io.IOException if there is an error
  1208. * @throws NullPointerException if dataToEncode is null
  1209. * @since 2.1
  1210. */
  1211. public static void encodeToFile( byte[] dataToEncode, String filename )
  1212. throws java.io.IOException {
  1213. if( dataToEncode == null ){
  1214. throw new NullPointerException( "Data to encode was null." );
  1215. } // end iff
  1216. Base64.OutputStream bos = null;
  1217. try {
  1218. bos = new Base64.OutputStream(
  1219. new java.io.FileOutputStream( filename ), Base64.ENCODE );
  1220. bos.write( dataToEncode );
  1221. } // end try
  1222. catch( java.io.IOException e ) {
  1223. throw e; // Catch and throw to execute finally{} block
  1224. } // end catch: java.io.IOException
  1225. finally {
  1226. try{ bos.close(); } catch( Exception e ){}
  1227. } // end finally
  1228. } // end encodeToFile
  1229. /**
  1230. * Convenience method for decoding data to a file.
  1231. *
  1232. * <p>As of v 2.3, if there is a error,
  1233. * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
  1234. * In earlier versions, it just returned false, but
  1235. * in retrospect that's a pretty poor way to handle it.</p>
  1236. *
  1237. * @param dataToDecode Base64-encoded data as a string
  1238. * @param filename Filename for saving decoded data
  1239. * @throws java.io.IOException if there is an error
  1240. * @since 2.1
  1241. */
  1242. public static void decodeToFile( String dataToDecode, String filename )
  1243. throws java.io.IOException {
  1244. Base64.OutputStream bos = null;
  1245. try{
  1246. bos = new Base64.OutputStream(
  1247. new java.io.FileOutputStream( filename ), Base64.DECODE );
  1248. bos.write( dataToDecode.getBytes( PREFERRED_ENCODING ) );
  1249. } // end try
  1250. catch( java.io.IOException e ) {
  1251. throw e; // Catch and throw to execute finally{} block
  1252. } // end catch: java.io.IOException
  1253. finally {
  1254. try{ bos.close(); } catch( Exception e ){}
  1255. } // end finally
  1256. } // end decodeToFile
  1257. /**
  1258. * Convenience method for reading a base64-encoded
  1259. * file and decoding it.
  1260. *
  1261. * <p>As of v 2.3, if there is a error,
  1262. * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
  1263. * In earlier versions, it just returned false, but
  1264. * in retrospect that's a pretty poor way to handle it.</p>
  1265. *
  1266. * @param filename Filename for reading encoded data
  1267. * @return decoded byte array
  1268. * @throws java.io.IOException if there is an error
  1269. * @since 2.1
  1270. */
  1271. public static byte[] decodeFromFile( String filename )
  1272. throws java.io.IOException {
  1273. byte[] decodedData = null;
  1274. Base64.InputStream bis = null;
  1275. try
  1276. {
  1277. // Set up some useful variables
  1278. java.io.File file = new java.io.File( filename );
  1279. byte[] buffer = null;
  1280. int length = 0;
  1281. int numBytes = 0;
  1282. // Check for size of file
  1283. if( file.length() > Integer.MAX_VALUE )
  1284. {
  1285. throw new java.io.IOException( "File is too big for this convenience method (" + file.length() + " bytes)." );
  1286. } // end if: file too big for int index
  1287. buffer = new byte[ (int)file.length() ];
  1288. // Open a stream
  1289. bis = new Base64.InputStream(
  1290. new java.io.BufferedInputStream(
  1291. new java.io.FileInputStream( file ) ), Base64.DECODE );
  1292. // Read until done
  1293. while( ( numBytes = bis.read( buffer, length, 4096 ) ) >= 0 ) {
  1294. length += numBytes;
  1295. } // end while
  1296. // Save in a variable to return
  1297. decodedData = new byte[ length ];
  1298. System.arraycopy( buffer, 0, decodedData, 0, length );
  1299. } // end try
  1300. catch( java.io.IOException e ) {
  1301. throw e; // Catch and release to execute finally{}
  1302. } // end catch: java.io.IOException
  1303. finally {
  1304. try{ bis.close(); } catch( Exception e) {}
  1305. } // end finally
  1306. return decodedData;
  1307. } // end decodeFromFile
  1308. /**
  1309. * Convenience method for reading a binary file
  1310. * and base64-encoding it.
  1311. *
  1312. * <p>As of v 2.3, if there is a error,
  1313. * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
  1314. * In earlier versions, it just returned false, but
  1315. * in retrospect that's a pretty poor way to handle it.</p>
  1316. *
  1317. * @param filename Filename for reading binary data
  1318. * @return base64-encoded string
  1319. * @throws java.io.IOException if there is an error
  1320. * @since 2.1
  1321. */
  1322. public static String encodeFromFile( String filename )
  1323. throws java.io.IOException {
  1324. String encodedData = null;
  1325. Base64.InputStream bis = null;
  1326. try
  1327. {
  1328. // Set up some useful variables
  1329. java.io.File file = new java.io.File( filename );
  1330. byte[] buffer = new byte[ Math.max((int)(file.length() * 1.4+1),40) ]; // Need max() for math on small files (v2.2.1); Need +1 for a few corner cases (v2.3.5)
  1331. int length = 0;
  1332. int numBytes = 0;
  1333. // Open a stream
  1334. bis = new Base64.InputStream(
  1335. new java.io.BufferedInputStream(
  1336. new java.io.FileInputStream( file ) ), Base64.ENCODE );
  1337. // Read until done
  1338. while( ( numBytes = bis.read( buffer, length, 4096 ) ) >= 0 ) {
  1339. length += numBytes;
  1340. } // end while
  1341. // Save in a variable to return
  1342. encodedData = new String( buffer, 0, length, Base64.PREFERRED_ENCODING );
  1343. } // end try
  1344. catch( java.io.IOException e ) {
  1345. throw e; // Catch and release to execute finally{}
  1346. } // end catch: java.io.IOException
  1347. finally {
  1348. try{ bis.close(); } catch( Exception e) {}
  1349. } // end finally
  1350. return encodedData;
  1351. } // end encodeFromFile
  1352. /**
  1353. * Reads <tt>infile</tt> and encodes it to <tt>outfile</tt>.
  1354. *
  1355. * @param infile Input file
  1356. * @param outfile Output file
  1357. * @throws java.io.IOException if there is an error
  1358. * @since 2.2
  1359. */
  1360. public static void encodeFileToFile( String infile, String outfile )
  1361. throws java.io.IOException {
  1362. String encoded = Base64.encodeFromFile( infile );
  1363. java.io.OutputStream out = null;
  1364. try{
  1365. out = new java.io.BufferedOutputStream(
  1366. new java.io.FileOutputStream( outfile ) );
  1367. out.write( encoded.getBytes("US-ASCII") ); // Strict, 7-bit output.
  1368. } // end try
  1369. catch( java.io.IOException e ) {
  1370. throw e; // Catch and release to execute finally{}
  1371. } // end catch
  1372. finally {
  1373. try { out.close(); }
  1374. catch( Exception ex ){}
  1375. } // end finally
  1376. } // end encodeFileToFile
  1377. /**
  1378. * Reads <tt>infile</tt> and decodes it to <tt>outfile</tt>.
  1379. *
  1380. * @param infile Input file
  1381. * @param outfile Output file
  1382. * @throws java.io.IOException if there is an error
  1383. * @since 2.2
  1384. */
  1385. public static void decodeFileToFile( String infile, String outfile )
  1386. throws java.io.IOException {
  1387. byte[] decoded = Base64.decodeFromFile( infile );
  1388. java.io.OutputStream out = null;
  1389. try{
  1390. out = new java.io.BufferedOutputStream(
  1391. new java.io.FileOutputStream( outfile ) );
  1392. out.write( decoded );
  1393. } // end try
  1394. catch( java.io.IOException e ) {
  1395. throw e; // Catch and release to execute finally{}
  1396. } // end catch
  1397. finally {
  1398. try { out.close(); }
  1399. catch( Exception ex ){}
  1400. } // end finally
  1401. } // end decodeFileToFile
  1402. /* ******** I N N E R C L A S S I N P U T S T R E A M ******** */
  1403. /**
  1404. * A {@link Base64.InputStream} will read data from another
  1405. * <tt>java.io.InputStream</tt>, given in the constructor,
  1406. * and encode/decode to/from Base64 notation on the fly.
  1407. *
  1408. * @see Base64
  1409. * @since 1.3
  1410. */
  1411. public static class InputStream extends java.io.FilterInputStream {
  1412. private boolean encode; // Encoding or decoding
  1413. private int position; // Current position in the buffer
  1414. private byte[] buffer; // Small buffer holding converted data
  1415. private int bufferLength; // Length of buffer (3 or 4)
  1416. private int numSigBytes; // Number of meaningful bytes in the buffer
  1417. private int lineLength;
  1418. private boolean breakLines; // Break lines at less than 80 characters
  1419. private int options; // Record options used to create the stream.
  1420. private byte[] decodabet; // Local copies to avoid extra method calls
  1421. /**
  1422. * Constructs a {@link Base64.InputStream} in DECODE mode.
  1423. *
  1424. * @param in the <tt>java.io.InputStream</tt> from which to read data.
  1425. * @since 1.3
  1426. */
  1427. public InputStream( java.io.InputStream in ) {
  1428. this( in, DECODE );
  1429. } // end constructor
  1430. /**
  1431. * Constructs a {@link Base64.InputStream} in
  1432. * either ENCODE or DECODE mode.
  1433. * <p>
  1434. * Valid options:<pre>
  1435. * ENCODE or DECODE: Encode or Decode as data is read.
  1436. * DO_BREAK_LINES: break lines at 76 characters
  1437. * (only meaningful when encoding)</i>
  1438. * </pre>
  1439. * <p>
  1440. * Example: <code>new Base64.InputStream( in, Base64.DECODE )</code>
  1441. *
  1442. *
  1443. * @param in the <tt>java.io.InputStream</tt> from which to read data.
  1444. * @param options Specified options
  1445. * @see Base64#ENCODE
  1446. * @see Base64#DECODE
  1447. * @see Base64#DO_BREAK_LINES
  1448. * @since 2.0
  1449. */
  1450. public InputStream( java.io.InputStream in, int options ) {
  1451. super( in );
  1452. this.options = options; // Record for later
  1453. this.breakLines = (options & DO_BREAK_LINES) > 0;
  1454. this.encode = (options & ENCODE) > 0;
  1455. this.bufferLength = encode ? 4 : 3;
  1456. this.buffer = new byte[ bufferLength ];
  1457. this.position = -1;
  1458. this.lineLength = 0;
  1459. this.decodabet = getDecodabet(options);
  1460. } // end constructor
  1461. /**
  1462. * Reads enough of the input stream to convert
  1463. * to/from Base64 and returns the next byte.
  1464. *
  1465. * @return next byte
  1466. * @since 1.3
  1467. */
  1468. @Override
  1469. public int read() throws java.io.IOException {
  1470. // Do we need to get data?
  1471. if( position < 0 ) {
  1472. if( encode ) {
  1473. byte[] b3 = new byte[3];
  1474. int numBinaryBytes = 0;
  1475. for( int i = 0; i < 3; i++ ) {
  1476. int b = in.read();
  1477. // If end of stream, b is -1.
  1478. if( b >= 0 ) {
  1479. b3[i] = (byte)b;
  1480. numBinaryBytes++;
  1481. } else {
  1482. break; // out of for loop
  1483. } // end else: end of stream
  1484. } // end for: each needed input byte
  1485. if( numBinaryBytes > 0 ) {
  1486. encode3to4( b3, 0, numBinaryBytes, buffer, 0, options );
  1487. position = 0;
  1488. numSigBytes = 4;
  1489. } // end if: got data
  1490. else {
  1491. return -1; // Must be end of stream
  1492. } // end else
  1493. } // end if: encoding
  1494. // Else decoding
  1495. else {
  1496. byte[] b4 = new byte[4];
  1497. int i = 0;
  1498. for( i = 0; i < 4; i++ ) {
  1499. // Read four "meaningful" bytes:
  1500. int b = 0;
  1501. do{ b = in.read(); }
  1502. while( b >= 0 && decodabet[ b & 0x7f ] <= WHITE_SPACE_ENC );
  1503. if( b < 0 ) {
  1504. break; // Reads a -1 if end of stream
  1505. } // end if: end of stream
  1506. b4[i] = (byte)b;
  1507. } // end for: each needed input byte
  1508. if( i == 4 ) {
  1509. numSigBytes = decode4to3( b4, 0, buffer, 0, options );
  1510. position = 0;
  1511. } // end if: got four characters
  1512. else if( i == 0 ){
  1513. return -1;
  1514. } // end else if: also padded correctly
  1515. else {
  1516. // Must have broken out from above.
  1517. throw new java.io.IOException( "Improperly padded Base64 input." );
  1518. } // end
  1519. } // end else: decode
  1520. } // end else: get data
  1521. // Got data?
  1522. if( position >= 0 ) {
  1523. // End of relevant data?
  1524. if( /*!encode &&*/ position >= numSigBytes ){
  1525. return -1;
  1526. } // end if: got data
  1527. if( encode && breakLines && lineLength >= MAX_LINE_LENGTH ) {
  1528. lineLength = 0;
  1529. return '\n';
  1530. } // end if
  1531. else {
  1532. lineLength++; // This isn't important when decoding
  1533. // but throwing an extra "if" seems
  1534. // just as wasteful.
  1535. int b = buffer[ position++ ];
  1536. if( position >= bufferLength ) {
  1537. position = -1;
  1538. } // end if: end
  1539. return b & 0xFF; // This is how you "cast" a byte that's
  1540. // intended to be unsigned.
  1541. } // end else
  1542. } // end if: position >= 0
  1543. // Else error
  1544. else {
  1545. throw new java.io.IOException( "Error in Base64 code reading stream." );
  1546. } // end else
  1547. } // end read
  1548. /**
  1549. * Calls {@link #read()} repeatedly until the end of stream
  1550. * is reached or <var>len</var> bytes are read.
  1551. * Returns number of bytes read into array or -1 if
  1552. * end of stream is encountered.
  1553. *
  1554. * @param dest array to hold values
  1555. * @param off offset for array
  1556. * @param len max number of bytes to read into array
  1557. * @return bytes read into array or -1 if end of stream is encountered.
  1558. * @since 1.3
  1559. */
  1560. @Override
  1561. public int read( byte[] dest, int off, int len )
  1562. throws java.io.IOException {
  1563. int i;
  1564. int b;
  1565. for( i = 0; i < len; i++ ) {
  1566. b = read();
  1567. if( b >= 0 ) {
  1568. dest[off + i] = (byte) b;
  1569. }
  1570. else if( i == 0 ) {
  1571. return -1;
  1572. }
  1573. else {
  1574. break; // Out of 'for' loop
  1575. } // Out of 'for' loop
  1576. } // end for: each byte read
  1577. return i;
  1578. } // end read
  1579. } // end inner class InputStream
  1580. /* ******** I N N E R C L A S S O U T P U T S T R E A M ******** */
  1581. /**
  1582. * A {@link Base64.OutputStream} will write data to another
  1583. * <tt>java.io.OutputStream</tt>, given in the constructor,
  1584. * and encode/decode to/from Base64 notation on the fly.
  1585. *
  1586. * @see Base64
  1587. * @since 1.3
  1588. */
  1589. public static class OutputStream extends java.io.FilterOutputStream {
  1590. private boolean encode;
  1591. private int position;
  1592. private byte[] buffer;
  1593. private int bufferLength;
  1594. private int lineLength;
  1595. private boolean breakLines;
  1596. private byte[] b4; // Scratch used in a few places
  1597. private boolean suspendEncoding;
  1598. private int options; // Record for later
  1599. private byte[] decodabet; // Local copies to avoid extra method calls
  1600. /**
  1601. * Constructs a {@link Base64.OutputStream} in ENCODE mode.
  1602. *
  1603. * @param out the <tt>java.io.OutputStream</tt> to which data will be written.
  1604. * @since 1.3
  1605. */
  1606. public OutputStream( java.io.OutputStream out ) {
  1607. this( out, ENCODE );
  1608. } // end constructor
  1609. /**
  1610. * Constructs a {@link Base64.OutputStream} in
  1611. * either ENCODE or DECODE mode.
  1612. * <p>
  1613. * Valid options:<pre>
  1614. * ENCODE or DECODE: Encode or Decode as data is read.
  1615. * DO_BREAK_LINES: don't break lines at 76 characters
  1616. * (only meaningful when encoding)</i>
  1617. * </pre>
  1618. * <p>
  1619. * Example: <code>new Base64.OutputStream( out, Base64.ENCODE )</code>
  1620. *
  1621. * @param out the <tt>java.io.OutputStream</tt> to which data will be written.
  1622. * @param options Specified options.
  1623. * @see Base64#ENCODE
  1624. * @see Base64#DECODE
  1625. * @see Base64#DO_BREAK_LINES
  1626. * @since 1.3
  1627. */
  1628. public OutputStream( java.io.OutputStream out, int options ) {
  1629. super( out );
  1630. this.breakLines = (options & DO_BREAK_LINES) != 0;
  1631. this.encode = (options & ENCODE) != 0;
  1632. this.bufferLength = encode ? 3 : 4;
  1633. this.buffer = new byte[ bufferLength ];
  1634. this.position = 0;
  1635. this.lineLength = 0;
  1636. this.suspendEncoding = false;
  1637. this.b4 = new byte[4];
  1638. this.options = options;
  1639. this.decodabet = getDecodabet(options);
  1640. } // end constructor
  1641. /**
  1642. * Writes the byte to the output stream after
  1643. * converting to/from Base64 notation.
  1644. * When encoding, bytes are buffered three
  1645. * at a time before the output stream actually
  1646. * gets a write() call.
  1647. * When decoding, bytes are buffered four
  1648. * at a time.
  1649. *
  1650. * @param theByte the byte to write
  1651. * @since 1.3
  1652. */
  1653. @Override
  1654. public void write(int theByte)
  1655. throws java.io.IOException {
  1656. // Encoding suspended?
  1657. if( suspendEncoding ) {
  1658. this.out.write( theByte );
  1659. return;
  1660. } // end if: supsended
  1661. // Encode?
  1662. if( encode ) {
  1663. buffer[ position++ ] = (byte)theByte;
  1664. if( position >= bufferLength ) { // Enough to encode.
  1665. this.out.write( encode3to4( b4, buffer, bufferLength, options ) );
  1666. lineLength += 4;
  1667. if( breakLines && lineLength >= MAX_LINE_LENGTH ) {
  1668. this.out.write( NEW_LINE );
  1669. lineLength = 0;
  1670. } // end if: end of line
  1671. position = 0;
  1672. } // end if: enough to output
  1673. } // end if: encoding
  1674. // Else, Decoding
  1675. else {
  1676. // Meaningful Base64 character?
  1677. if( decodabet[ theByte & 0x7f ] > WHITE_SPACE_ENC ) {
  1678. buffer[ position++ ] = (byte)theByte;
  1679. if( position >= bufferLength ) { // Enough to output.
  1680. int len = Base64.decode4to3( buffer, 0, b4, 0, options );
  1681. out.write( b4, 0, len );
  1682. position = 0;
  1683. } // end if: enough to output
  1684. } // end if: meaningful base64 character
  1685. else if( decodabet[ theByte & 0x7f ] != WHITE_SPACE_ENC ) {
  1686. throw new java.io.IOException( "Invalid character in Base64 data." );
  1687. } // end else: not white space either
  1688. } // end else: decoding
  1689. } // end write
  1690. /**
  1691. * Calls {@link #write(int)} repeatedly until <var>len</var>
  1692. * bytes are written.
  1693. *
  1694. * @param theBytes array from which to read bytes
  1695. * @param off offset for array
  1696. * @param len max number of bytes to read into array
  1697. * @since 1.3
  1698. */
  1699. @Override
  1700. public void write( byte[] theBytes, int off, int len )
  1701. throws java.io.IOException {
  1702. // Encoding suspended?
  1703. if( suspendEncoding ) {
  1704. this.out.write( theBytes, off, len );
  1705. return;
  1706. } // end if: supsended
  1707. for( int i = 0; i < len; i++ ) {
  1708. write( theBytes[ off + i ] );
  1709. } // end for: each byte written
  1710. } // end write
  1711. /**
  1712. * Method added by PHIL. [Thanks, PHIL. -Rob]
  1713. * This pads the buffer without closing the stream.
  1714. * @throws java.io.IOException if there's an error.
  1715. */
  1716. public void flushBase64() throws java.io.IOException {
  1717. if( position > 0 ) {
  1718. if( encode ) {
  1719. out.write( encode3to4( b4, buffer, position, options ) );
  1720. position = 0;
  1721. } // end if: encoding
  1722. else {
  1723. throw new java.io.IOException( "Base64 input not properly padded." );
  1724. } // end else: decoding
  1725. } // end if: buffer partially full
  1726. } // end flush
  1727. /**
  1728. * Flushes and closes (I think, in the superclass) the stream.
  1729. *
  1730. * @since 1.3
  1731. */
  1732. @Override
  1733. public void close() throws java.io.IOException {
  1734. // 1. Ensure that pending characters are written
  1735. flushBase64();
  1736. // 2. Actually close the stream
  1737. // Base class both flushes and closes.
  1738. super.close();
  1739. buffer = null;
  1740. out = null;
  1741. } // end close
  1742. /**
  1743. * Suspends encoding of the stream.
  1744. * May be helpful if you need to embed a piece of
  1745. * base64-encoded data in a stream.
  1746. *
  1747. * @throws java.io.IOException if there's an error flushing
  1748. * @since 1.5.1
  1749. */
  1750. public void suspendEncoding() throws java.io.IOException {
  1751. flushBase64();
  1752. this.suspendEncoding = true;
  1753. } // end suspendEncoding
  1754. /**
  1755. * Resumes encoding of the stream.
  1756. * May be helpful if you need to embed a piece of
  1757. * base64-encoded data in a stream.
  1758. *
  1759. * @since 1.5.1
  1760. */
  1761. public void resumeEncoding() {
  1762. this.suspendEncoding = false;
  1763. } // end resumeEncoding
  1764. } // end inner class OutputStream
  1765. } // end class Base64