/* * =========================================================================== * PD4ML: HTML to PDF Converter for Java. * DXL-to-PDF converting agent * * http://pd4ml.com, 2007-2008 * =========================================================================== */ import java.awt.Dimension; import java.awt.Insets; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.Reader; import java.io.StringReader; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.Map; import lotus.domino.AgentBase; import lotus.domino.AgentContext; import lotus.domino.Database; import lotus.domino.Document; import lotus.domino.DocumentCollection; import lotus.domino.DxlExporter; import lotus.domino.EmbeddedObject; import lotus.domino.RichTextItem; import lotus.domino.Session; import org.xml.sax.SAXException; import org.zefer.pd4ml.PD4Constants; import org.zefer.pd4ml.PD4ML; import org.zefer.pd4ml.PD4PageMark; public class PdfAgentR7 extends AgentBase { private final static String xslName = "dxl4pd4ml.xsl"; /* configuration switch: XSL location */ private final static boolean readXslFromJar = true; private final static String xslDocumentFormName = "XSL4PD4ML"; private final static String xslDocumentFieldName = "XSLT"; private final static boolean dontPassAttachmentsToXalan = true; private static boolean rtf = false; public static void main( String args[] ) { if ( args.length < 1 ) { System.out.println( "Input DXL parameter is missing" ); System.exit(1); } try { String dxlPath = args[0]; String pdfPath = dxlPath + (rtf ? ".rtf" : ".pdf"); int dot = dxlPath.lastIndexOf('.'); if ( dot > 0 ) { pdfPath = pdfPath.subSequence(0, dot) + ".pdf"; } String xml = readFile( dxlPath ); String xsl = readFile( xslName ); long start = System.currentTimeMillis(); // System.out.println(xml); String html = transformXML(xml, xsl); long middle = System.currentTimeMillis(); System.out.println("XSL transformation: " + (middle-start) + "ms"); System.out.println("HTML: " + html); // File pdf = File.createTempFile("pd4ml", ".pdf"); File pdf = new File( pdfPath ); java.io.FileOutputStream fos = new java.io.FileOutputStream(pdf); generatePDF( html, fos, PD4Constants.A4, "c:/windows/fonts", null ); // "DXL to PDF convesion result. $[page] of $[total]"); if ( rtf ) { Runtime.getRuntime().exec( "C:\\Program Files\\Microsoft Office\\OFFICE11\\winword.exe " + pdf.getAbsolutePath() ); } else { Runtime.getRuntime().exec( "C:\\Program Files\\Adobe\\Reader 11.0\\Reader\\AcroRd32.exe \"" + pdf.getAbsolutePath() + "\"" ); } } catch (Exception e) { e.printStackTrace(); } } public void NotesMain() { try { Session session = getSession(); AgentContext agentContext = session.getAgentContext(); System.out.println("AGENT start."); Database db = agentContext.getCurrentDatabase(); String xsl = null; if (readXslFromJar) { xsl = getXsl(); // the method uses Java ClassLoader to read XSL. Works for v6.5.4, but fails for older versions // (according to some reports) } else { // bulky, but a standard for Domino way to store XSL documents. // useful for debug and XSL refining DocumentCollection dcx = db.search("@Contains(Form; \"" + xslDocumentFormName + "\")"); Document xsldoc = dcx.getFirstDocument(); if (xsldoc != null) { xsl = xsldoc.getItemValueString(xslDocumentFieldName); } else { // looks like there is no form named XSL4PD4ML // try to read XSL from JAR file throw new IOException( "Can not find " + xslName); } } // System.out.println("XSL: " + xsl); // collect selected documents DocumentCollection dc = agentContext.getUnprocessedDocuments(); Document doc = dc.getFirstDocument(); while (doc != null) { Document tmp = db.createDocument(); RichTextItem rti = tmp.createRichTextItem("PD4MLBody"); doc.renderToRTItem(rti); DxlExporter dxl = session.createDxlExporter(); dxl.setConvertNotesBitmapsToGIF(true); dxl.setOutputDOCTYPE(false); String xml = dxl.exportDxl(tmp); // System.out.println("DXL FORM: " + xml); String html = transformXML(xml, xsl); // System.out.println("HTML: " + html); File pdf = File.createTempFile("pd4ml", ".pdf"); java.io.FileOutputStream fos = new java.io.FileOutputStream(pdf); generatePDF( html, fos, PD4Constants.A4, "java:/fonts", // the reference points to a fonts collection packed to a JAR. // an alternative would be to reference a local font directory: "c:/windows/fonts" // read more about font directory configuration: http://pd4ml.com/reference.htm#7.1 "DXL to PDF convesion result. $[page] of $[total]"); doc.removeItem("PdfAttachment"); doc.save(true, true); RichTextItem obj = (RichTextItem) doc.getFirstItem("PdfAttachment"); if (obj == null) { RichTextItem attx = doc.createRichTextItem("PdfAttachment"); attx.embedObject(EmbeddedObject.EMBED_ATTACHMENT, null, pdf.getAbsolutePath(), "pdfattachment"); fos.flush(); fos.close(); } doc.save(true, true); pdf.delete(); doc = dc.getNextDocument(); } System.out.println("AGENT done."); } catch (SAXException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } public static final String extractAttachments( String body ) throws IOException { if (body != null) { int index01 = body.indexOf( "" ); index02 = body.indexOf( "", index01 + 1 ); String fileName = "bin"; int name01 = body.lastIndexOf("name='", index02); if ( name01 > 0 ) { name01 += 6; int name02 = body.indexOf('\'', name01); if ( name02 > 0 ) { fileName = body.substring(name01,name02); } } int endtag = body.indexOf( ">", index01 + 1 ); String fileContent = body.substring( endtag + 1, index02 ); byte[] bytes = Base64.decode( fileContent ); File file = File.createTempFile("attachment", "." + fileName); file.deleteOnExit(); FileOutputStream fos = new FileOutputStream(file); fos.write(bytes); String tmpFileName = file.toURI().toString(); sb.append( tmpFileName ); sb.append( "" ); index02 += 11; index01 = body.indexOf( " 0) { pd4ml.useTTF(fontsDir, true); } if (footerBody != null && footerBody.length() > 0) { PD4PageMark footer = new PD4PageMark(); footer.setAreaHeight(-1); footer.setHtmlTemplate(footerBody); pd4ml.setPageFooter(footer); } Map m = new HashMap(); m.put(PD4Constants.PD4ML_CACHE_IMAGES_IN_TMP_DIR, "true"); // m.put(PD4Constants.PD4ML_DOCUMENT_VIEW_MODE, "SinglePage"); pd4ml.setDynamicParams(m); if ( rtf ) { pd4ml.outputFormat(PD4Constants.RTF); } // pd4ml.generatePdfa(true); pd4ml.enableDebugInfo(); // in Lotus environment the debug info appears under File->Tools->Show Java Debug Console pd4ml.render( new StringReader(inputHTML), fos, new URL("file:."), "utf-8"); fos.flush(); fos.close(); } public static final String transformXML(String xml, String xsl) throws SAXException, MalformedURLException, IOException { if ( dontPassAttachmentsToXalan ) { xml = extractAttachments(xml); System.out.println("DXL WITHOUT ATTACHMENTS: " + xml); } try { java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream(); // javax.xml.transform.Source xmlSource = new javax.xml.transform.stream.StreamSource(new StringReader(xml)); // javax.xml.transform.Source xsltSource = new javax.xml.transform.stream.StreamSource(new StringReader(xsl)); javax.xml.transform.Result result = new javax.xml.transform.stream.StreamResult(baos); javax.xml.parsers.SAXParserFactory spf = javax.xml.parsers.SAXParserFactory.newInstance(); spf.setNamespaceAware(true); spf.setValidating(false); // Turn off validation spf.setFeature("http://xml.org/sax/features/validation", false); // spf.setFeature("http://xml.org/sax/features/string-interning", false); spf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); org.xml.sax.XMLReader reader = spf.newSAXParser().getXMLReader(); javax.xml.transform.Source xmlSource = new javax.xml.transform.sax.SAXSource(reader,new org.xml.sax.InputSource(new StringReader(xml))); org.xml.sax.XMLReader reader2 = spf.newSAXParser().getXMLReader(); javax.xml.transform.Source xsltSource = new javax.xml.transform.sax.SAXSource(reader2,new org.xml.sax.InputSource(new StringReader(xsl))); javax.xml.transform.TransformerFactory transFact = javax.xml.transform.TransformerFactory.newInstance(); // R8.5 workaround: http://code.google.com/p/googleappengine/issues/detail?id=1452 // javax.xml.transform.TransformerFactory transFact = // javax.xml.transform.TransformerFactory.newInstance("org.apache.xalan.processor.TransformerFactoryImpl", null); javax.xml.transform.Transformer trans = transFact.newTransformer(xsltSource); // System.out.println("TRANS: " + trans); System.out.println("TRANS: " + System.getProperty("java.version")); trans.transform(xmlSource, result); return baos.toString("utf-8"); } catch (javax.xml.transform.TransformerException e) { e.printStackTrace(); // } catch (javax.xml.transform.TransformerConfigurationException e) // { // e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return null; } /* // Transformer code for versions prior R7 import com.lotus.xml.xml4j2dom.XML4JLiaison4dom; import com.lotus.xsl.XSLProcessor; import com.lotus.xsl.XSLTInputSource; import com.lotus.xsl.XSLTResultTarget; public static final String transformXML(String xml, String xsl) throws SAXException, MalformedURLException, IOException { XSLProcessor xp = new XSLProcessor(new XML4JLiaison4dom()); StringReader xmlSource2 = new StringReader(xml); StringReader xslSource2 = new StringReader(xsl); StringWriter sw = new StringWriter(); XSLTInputSource xs = new XSLTInputSource(xmlSource2); XSLTInputSource xt = new XSLTInputSource(xslSource2); XSLTResultTarget tout = new XSLTResultTarget(sw); xp.process(xs, xt, tout); return sw.toString(); } */ public String getXsl() throws IOException { ByteArrayOutputStream fos = new ByteArrayOutputStream(); byte buffer[] = new byte[2048]; InputStream is = getClass().getClassLoader().getResourceAsStream(xslName); BufferedInputStream bis = new BufferedInputStream(is); int read; do { read = bis.read(buffer, 0, buffer.length); if (read > 0) { fos.write(buffer, 0, read); } } while (read > -1); fos.close(); bis.close(); is.close(); return new String(fos.toByteArray()); } /* * The two methods below are useful for offline debug. In order to run the Java class * offline you need in the classpath the following: * * pd4ml.jar (or pd4ml_demo.jar) * ss_css2.jar * xml4j.jar * lotusXSL.jar * notes.jar * * Please do not forget to pre-configure fonts dir with the command line call: * java -jar pd4ml.jar -configure.fonts c:/windows/fonts * * */ private final static String XXeadFile( String path ) throws Exception { char c[] = new char[2048]; StringBuffer result = new StringBuffer(); Reader in = new InputStreamReader(new FileInputStream(path), "UTF-8"); int len = 0; while( (len = in.read(c)) > 0 ) { result.append( new String(c, 0, len) ); } return result.toString(); } private final static String readFile( String path ) throws Exception { File f = new File( path ); FileInputStream is = new FileInputStream(f); BufferedInputStream bis = new BufferedInputStream(is); ByteArrayOutputStream fos = new ByteArrayOutputStream(); byte buffer[] = new byte[2048]; int read; do { read = is.read(buffer, 0, buffer.length); if (read > 0) { // something to put down fos.write(buffer, 0, read); } } while (read > -1); fos.close(); bis.close(); is.close(); return fos.toString("UTF-8"); } /** * Encodes and decodes to and from Base64 notation. * *

* Change Log: *

* * *

* I am placing this code in the Public Domain. Do with it as you will. * This software comes with no guarantees or warranties but with * plenty of well-wishing instead! * Please visit http://iharder.net/base64 * periodically to check for updates or to contribute improvements. *

* * @author Robert Harder * @author rob@iharder.net * @version 2.1 */ public static class Base64 { /* ******** P U B L I C F I E L D S ******** */ /** No options specified. Value is zero. */ public final static int NO_OPTIONS = 0; /** Specify encoding. */ public final static int ENCODE = 1; /** Specify decoding. */ public final static int DECODE = 0; /** Specify that data should be gzip-compressed. */ public final static int GZIP = 2; /** Don't break lines when encoding (violates strict Base64 specification) */ public final static int DONT_BREAK_LINES = 8; /* ******** P R I V A T E F I E L D S ******** */ /** The equals sign (=) as a byte. */ private final static byte EQUALS_SIGN = (byte)'='; /** Preferred encoding. */ private final static String PREFERRED_ENCODING = "UTF-8"; /** The 64 valid Base64 values. */ private final static byte[] ALPHABET; private final static byte[] _NATIVE_ALPHABET = /* May be something funny like EBCDIC */ { (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z', (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'+', (byte)'/' }; /** Determine which ALPHABET to use. */ static { byte[] __bytes; try { __bytes = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".getBytes( PREFERRED_ENCODING ); } // end try catch (java.io.UnsupportedEncodingException use) { __bytes = _NATIVE_ALPHABET; // Fall back to native encoding } // end catch ALPHABET = __bytes; } // end static /** * Translates a Base64 value to either its 6-bit reconstruction value * or a negative number indicating some other meaning. **/ private final static byte[] DECODABET = { -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8 -5,-5, // Whitespace: Tab and Linefeed -9,-9, // Decimal 11 - 12 -5, // Whitespace: Carriage Return -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26 -9,-9,-9,-9,-9, // Decimal 27 - 31 -5, // Whitespace: Space -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42 62, // Plus sign at decimal 43 -9,-9,-9, // Decimal 44 - 46 63, // Slash at decimal 47 52,53,54,55,56,57,58,59,60,61, // Numbers zero through nine -9,-9,-9, // Decimal 58 - 60 -1, // Equals sign at decimal 61 -9,-9,-9, // Decimal 62 - 64 0,1,2,3,4,5,6,7,8,9,10,11,12,13, // Letters 'A' through 'N' 14,15,16,17,18,19,20,21,22,23,24,25, // Letters 'O' through 'Z' -9,-9,-9,-9,-9,-9, // Decimal 91 - 96 26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm' 39,40,41,42,43,44,45,46,47,48,49,50,51, // Letters 'n' through 'z' -9,-9,-9,-9 // Decimal 123 - 126 /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ }; // I think I end up not using the BAD_ENCODING indicator. //private final static byte BAD_ENCODING = -9; // Indicates error in encoding private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding /** Defeats instantiation. */ private Base64(){} /* ******** D E C O D I N G M E T H O D S ******** */ /** * Decodes four bytes from array source * and writes the resulting bytes (up to three of them) * to destination. * The source and destination arrays can be manipulated * anywhere along their length by specifying * srcOffset and destOffset. * This method does not check to make sure your arrays * are large enough to accomodate srcOffset + 4 for * the source array or destOffset + 3 for * the destination array. * This method returns the actual number of bytes that * were converted from the Base64 encoding. * * * @param source the array to convert * @param srcOffset the index where conversion begins * @param destination the array to hold the conversion * @param destOffset the index where output will be put * @return the number of decoded bytes converted * @since 1.3 */ private static int decode4to3( byte[] source, int srcOffset, byte[] destination, int destOffset ) { // Example: Dk== if( source[ srcOffset + 2] == EQUALS_SIGN ) { // Two ways to do the same thing. Don't know which way I like best. //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) // | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 ); int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 ) | ( ( DECODABET[ source[ srcOffset + 1] ] & 0xFF ) << 12 ); destination[ destOffset ] = (byte)( outBuff >>> 16 ); return 1; } // Example: DkL= else if( source[ srcOffset + 3 ] == EQUALS_SIGN ) { // Two ways to do the same thing. Don't know which way I like best. //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ); int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 ) | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 ) | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6 ); destination[ destOffset ] = (byte)( outBuff >>> 16 ); destination[ destOffset + 1 ] = (byte)( outBuff >>> 8 ); return 2; } // Example: DkLE else { try{ // Two ways to do the same thing. Don't know which way I like best. //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ) // | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 ); int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 ) | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 ) | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6) | ( ( DECODABET[ source[ srcOffset + 3 ] ] & 0xFF ) ); destination[ destOffset ] = (byte)( outBuff >> 16 ); destination[ destOffset + 1 ] = (byte)( outBuff >> 8 ); destination[ destOffset + 2 ] = (byte)( outBuff ); return 3; }catch( Exception e){ System.out.println(""+source[srcOffset]+ ": " + ( DECODABET[ source[ srcOffset ] ] ) ); System.out.println(""+source[srcOffset+1]+ ": " + ( DECODABET[ source[ srcOffset + 1 ] ] ) ); System.out.println(""+source[srcOffset+2]+ ": " + ( DECODABET[ source[ srcOffset + 2 ] ] ) ); System.out.println(""+source[srcOffset+3]+ ": " + ( DECODABET[ source[ srcOffset + 3 ] ] ) ); return -1; } //e nd catch } } // end decodeToBytes /** * Very low-level access to decoding ASCII characters in * the form of a byte array. Does not support automatically * gunzipping or any other "fancy" features. * * @param source The Base64 encoded data * @param off The offset of where to begin decoding * @param len The length of characters to decode * @return decoded data * @since 1.3 */ public static byte[] decode( byte[] source, int off, int len ) { int len34 = len * 3 / 4; byte[] outBuff = new byte[ len34 ]; // Upper limit on size of output int outBuffPosn = 0; byte[] b4 = new byte[4]; int b4Posn = 0; int i = 0; byte sbiCrop = 0; byte sbiDecode = 0; for( i = off; i < off+len; i++ ) { sbiCrop = (byte)(source[i] & 0x7f); // Only the low seven bits sbiDecode = DECODABET[ sbiCrop ]; if( sbiDecode >= WHITE_SPACE_ENC ) // White space, Equals sign or better { if( sbiDecode >= EQUALS_SIGN_ENC ) { b4[ b4Posn++ ] = sbiCrop; if( b4Posn > 3 ) { outBuffPosn += decode4to3( b4, 0, outBuff, outBuffPosn ); b4Posn = 0; // If that was the equals sign, break out of 'for' loop if( sbiCrop == EQUALS_SIGN ) break; } // end if: quartet built } // end if: equals sign or better } // end if: white space, equals sign or better else { System.err.println( "Bad Base64 input character at " + i + ": " + source[i] + "(decimal)" ); return null; } // end else: } // each input character byte[] out = new byte[ outBuffPosn ]; System.arraycopy( outBuff, 0, out, 0, outBuffPosn ); return out; } // end decode /** * Decodes data from Base64 notation, automatically * detecting gzip-compressed data and decompressing it. * * @param s the string to decode * @return the decoded data * @since 1.4 */ public static byte[] decode( String s ) { byte[] bytes; try { bytes = s.getBytes( PREFERRED_ENCODING ); } // end try catch( java.io.UnsupportedEncodingException uee ) { bytes = s.getBytes(); } // end catch // // Decode bytes = decode( bytes, 0, bytes.length ); // Check to see if it's gzip-compressed // GZIP Magic Two-Byte Number: 0x8b1f (35615) if( bytes != null && bytes.length >= 4 ) { int head = ((int)bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00); if( java.util.zip.GZIPInputStream.GZIP_MAGIC == head ) { java.io.ByteArrayInputStream bais = null; java.util.zip.GZIPInputStream gzis = null; java.io.ByteArrayOutputStream baos = null; byte[] buffer = new byte[2048]; int length = 0; try { baos = new java.io.ByteArrayOutputStream(); bais = new java.io.ByteArrayInputStream( bytes ); gzis = new java.util.zip.GZIPInputStream( bais ); while( ( length = gzis.read( buffer ) ) >= 0 ) { baos.write(buffer,0,length); } // end while: reading input // No error? Get new bytes. bytes = baos.toByteArray(); } // end try catch( java.io.IOException e ) { // Just return originally-decoded bytes } // end catch finally { try{ baos.close(); } catch( Exception e ){} try{ gzis.close(); } catch( Exception e ){} try{ bais.close(); } catch( Exception e ){} } // end finally } // end if: gzipped } // end if: bytes.length >= 2 return bytes; } // end decode } // end class Base64 }