/** * This is similar to getDecodedStreamByteArray(), except that the returned byte[] is not * necessarily exactly sized, and may be larger. Therefore the returned Integer gives the actual * valid size * * @param presize potential size to associate with byte array. * @return Object[] { byte[] data, Integer sizeActualData } */ public byte[] getDecodedStreamBytes(int presize) { // decompress the stream if (compressed) { try { ByteArrayInputStream streamInput = new ByteArrayInputStream(rawBytes); long rawStreamLength = rawBytes.length; InputStream input = getDecodedInputStream(streamInput, rawStreamLength); if (input == null) return null; int outLength; if (presize > 0) { outLength = presize; } else { outLength = Math.max(4096, (int) rawStreamLength); } ConservativeSizingByteArrayOutputStream out = new ConservativeSizingByteArrayOutputStream(outLength); byte[] buffer = new byte[(outLength > 4096) ? 4096 : 8192]; while (true) { int read = input.read(buffer); if (read <= 0) break; out.write(buffer, 0, read); } out.flush(); out.close(); input.close(); out.trim(); return out.relinquishByteArray(); } catch (IOException e) { logger.log(Level.FINE, "Problem decoding stream bytes: ", e); } } // we have an edited stream which isn't compressed yet, so just return // the raw bytes. else { return rawBytes; } return null; }
/** * Utility method for decoding the byte stream using the decode algorithem specified by the filter * parameter * * <p>The memory manger is called every time a stream is being decoded with an estimated size of * the decoded stream. Because many of the Filter algorithms use compression, further research * must be done to try and find the average amount of memory used by each of the algorithms. * * @return inputstream that has been decoded as defined by the streams filters. */ private InputStream getDecodedInputStream(InputStream streamInput, long streamLength) { // Make sure that the stream actually has data to decode, if it doesn't // make it null and return. if (streamInput == null || streamLength < 1) { return null; } InputStream input = streamInput; int bufferSize = Math.min(Math.max((int) streamLength, 64), 16 * 1024); input = new java.io.BufferedInputStream(input, bufferSize); // Search for crypt dictionary entry and decode params so that // named filters can be assigned correctly. if (library.securityManager != null) { // check see of there is a decodeParams for a crypt filter. HashMap decodeParams = library.getDictionary(entries, DECODEPARAM_KEY); input = library .getSecurityManager() .getEncryptionInputStream( getPObjectReference(), library.getSecurityManager().getDecryptionKey(), decodeParams, input, true); } // Get the filter name for the encoding type, which can be either // a Name or Vector. List filterNames = getFilterNames(); if (filterNames == null) return input; // Decode the stream data based on the filter names. // Loop through the filterNames and apply the filters in the order // in which they where found. for (Object filterName1 : filterNames) { // grab the name of the filter String filterName = filterName1.toString(); // System.out.println(" Decoding: " + filterName); if (filterName.equals("FlateDecode") || filterName.equals("/Fl") || filterName.equals("Fl")) { input = new FlateDecode(library, entries, input); } else if (filterName.equals("LZWDecode") || filterName.equals("/LZW") || filterName.equals("LZW")) { input = new LZWDecode(new BitStream(input), library, entries); } else if (filterName.equals("ASCII85Decode") || filterName.equals("/A85") || filterName.equals("A85")) { input = new ASCII85Decode(input); } else if (filterName.equals("ASCIIHexDecode") || filterName.equals("/AHx") || filterName.equals("AHx")) { input = new ASCIIHexDecode(input); } else if (filterName.equals("RunLengthDecode") || filterName.equals("/RL") || filterName.equals("RL")) { input = new RunLengthDecode(input); } else if (filterName.equals("CCITTFaxDecode") || filterName.equals("/CCF") || filterName.equals("CCF")) { // Leave empty so our else clause works } else if (filterName.equals("DCTDecode") || filterName.equals("/DCT") || filterName.equals("DCT")) { // Leave empty so our else clause works } else if ( // No short name, since no JBIG2 for inline images filterName.equals("JBIG2Decode")) { // Leave empty so our else clause works } else if ( // No short name, since no JPX for inline images filterName.equals("JPXDecode")) { // Leave empty so our else clause works } else { if (logger.isLoggable(Level.FINE)) { logger.fine("UNSUPPORTED:" + filterName + " " + entries); } } } return input; }