can be cached Submitted by: Paul Reavis <preavis@partnersoft.com> git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@194841 13f79535-47bb-0310-9956-ffa450edef68tags/fop-0_20_4-doc
@@ -9,6 +9,7 @@ package org.apache.fop.pdf; | |||
import java.io.ByteArrayOutputStream; | |||
import java.io.IOException; | |||
import java.io.*; | |||
public class ASCII85Filter extends PDFFilter { | |||
private static final char ASCII85_ZERO = 'z'; | |||
@@ -30,9 +31,7 @@ public class ASCII85Filter extends PDFFilter { | |||
return null; | |||
} | |||
public byte[] encode(byte[] data) { | |||
ByteArrayOutputStream buffer = new ByteArrayOutputStream(); | |||
public void encode(InputStream in, OutputStream out, int length) throws IOException { | |||
int i; | |||
int total = 0; | |||
@@ -40,16 +39,16 @@ public class ASCII85Filter extends PDFFilter { | |||
// first encode the majority of the data | |||
// each 4 byte group becomes a 5 byte group | |||
for (i = 0; i + 3 < data.length; i += 4) { | |||
for (i = 0; i + 3 < length; i += 4) { | |||
long val = ((data[i] << 24) | |||
long val = ((in.read() << 24) | |||
& 0xff000000L) // note: must have the L at the | |||
+ ((data[i + 1] << 16) & 0xff0000L) // end, otherwise you get into | |||
+ ((data[i + 2] << 8) & 0xff00L) // weird signed value problems | |||
+ (data[i + 3] & 0xffL); // cause we're using a full 32 bits | |||
+ ((in.read() << 16) & 0xff0000L) // end, otherwise you get into | |||
+ ((in.read() << 8) & 0xff00L) // weird signed value problems | |||
+ (in.read() & 0xffL); // cause we're using a full 32 bits | |||
byte[] conv = convertWord(val); | |||
buffer.write(conv, 0, conv.length); | |||
out.write(conv, 0, conv.length); | |||
} | |||
@@ -57,12 +56,12 @@ public class ASCII85Filter extends PDFFilter { | |||
// with n leftover bytes, we append 0 bytes to make a full group of 4 | |||
// then convert like normal (except not applying the special zero rule) | |||
// and write out the first n+1 bytes from the result | |||
if (i < data.length) { | |||
int n = data.length - i; | |||
if (i < length) { | |||
int n = length - i; | |||
byte[] lastdata = new byte[4]; | |||
for (int j = 0; j < 4; j++) { | |||
if (j < n) { | |||
lastdata[j] = data[i++]; | |||
lastdata[j] = (byte)in.read(); | |||
} else { | |||
lastdata[j] = 0; | |||
} | |||
@@ -82,18 +81,15 @@ public class ASCII85Filter extends PDFFilter { | |||
} | |||
} | |||
// assert n+1 <= 5 | |||
buffer.write(conv, 0, n + 1); | |||
out.write(conv, 0, n + 1); | |||
// System.out.println("ASCII85 end of data was "+n+" bytes long"); | |||
} | |||
// finally write the two character end of data marker | |||
buffer.write(ASCII85_EOD.getBytes(), 0, | |||
out.write(ASCII85_EOD.getBytes(), 0, | |||
ASCII85_EOD.getBytes().length); | |||
byte[] result = buffer.toByteArray(); | |||
// assert that we have the correct outgoing length | |||
/* | |||
* int in = (data.length % 4); | |||
@@ -103,8 +99,8 @@ public class ASCII85Filter extends PDFFilter { | |||
* System.out.println(" inlength = "+data.length+" inlength % 4 = "+(data.length % 4)+" outlength = "+(result.length-ASCII85_EOD.getBytes().length)+" outlength % 5 = "+((result.length-ASCII85_EOD.getBytes().length) % 5)); | |||
* } | |||
*/ | |||
return result; | |||
out.close(); | |||
} | |||
/** |
@@ -8,6 +8,7 @@ package org.apache.fop.pdf; | |||
import java.io.ByteArrayOutputStream; | |||
import java.io.IOException; | |||
import java.io.*; | |||
public class ASCIIHexFilter extends PDFFilter { | |||
private static final String ASCIIHEX_EOD = ">"; | |||
@@ -21,19 +22,16 @@ public class ASCIIHexFilter extends PDFFilter { | |||
return null; | |||
} | |||
public byte[] encode(byte[] data) { | |||
StringBuffer buffer = new StringBuffer(); | |||
for (int i = 0; i < data.length; i++) { | |||
int val = (int)(data[i] & 0xFF); | |||
public void encode(InputStream in, OutputStream out, int length) throws IOException { | |||
Writer writer = new OutputStreamWriter(out); | |||
for (int i = 0; i < length; i++) { | |||
int val = (int)(in.read() & 0xFF); | |||
if (val < 16) | |||
buffer.append("0"); | |||
buffer.append(Integer.toHexString(val)); | |||
writer.write("0"); | |||
writer.write(Integer.toHexString(val)); | |||
} | |||
buffer.append(ASCIIHEX_EOD); | |||
return buffer.toString().getBytes(); | |||
writer.write(ASCIIHEX_EOD); | |||
writer.close(); | |||
} | |||
} |
@@ -7,9 +7,11 @@ | |||
package org.apache.fop.pdf; | |||
import org.apache.fop.util.StreamUtilities; | |||
import java.io.ByteArrayOutputStream; | |||
import java.io.IOException; | |||
import java.io.*; | |||
/** | |||
* DCT Filter class. Right now it is just used as a dummy filter flag so | |||
@@ -28,8 +30,10 @@ public class DCTFilter extends PDFFilter { | |||
return null; | |||
} | |||
public byte[] encode(byte[] data) { | |||
return data; | |||
public void encode(InputStream in, OutputStream out, int length) throws IOException { | |||
StreamUtilities.streamCopy(in, out, length); | |||
out.close(); | |||
} | |||
} | |||
@@ -7,9 +7,12 @@ | |||
package org.apache.fop.pdf; | |||
import org.apache.fop.util.StreamUtilities; | |||
import java.io.ByteArrayOutputStream; | |||
import java.io.IOException; | |||
import java.util.zip.DeflaterOutputStream; | |||
import java.io.*; | |||
/** | |||
* A filter to deflate a stream. Note that the attributes for | |||
@@ -66,13 +69,12 @@ public class FlateFilter extends PDFFilter { | |||
* because these attributes are not supported. So the DecodeParms | |||
* should be retrieved after calling this method. | |||
*/ | |||
public byte[] encode(byte[] data) { | |||
ByteArrayOutputStream outArrayStream = new ByteArrayOutputStream(); | |||
public void encode(InputStream in, OutputStream out, int length) throws IOException { | |||
_predictor = PREDICTION_NONE; | |||
try { | |||
DeflaterOutputStream compressedStream = | |||
new DeflaterOutputStream(outArrayStream); | |||
compressedStream.write(data, 0, data.length); | |||
new DeflaterOutputStream(out); | |||
StreamUtilities.streamCopy(in, compressedStream, length); | |||
compressedStream.flush(); | |||
compressedStream.close(); | |||
} catch (IOException e) { | |||
@@ -80,7 +82,6 @@ public class FlateFilter extends PDFFilter { | |||
// + e.getMessage(), e); | |||
} | |||
return outArrayStream.toByteArray(); | |||
} | |||
public void setPredictor(int predictor) throws PDFFilterException { |
@@ -0,0 +1,104 @@ | |||
/* | |||
* $Id$ | |||
* Copyright (C) 2002 The Apache Software Foundation. All rights reserved. | |||
* For details on use and redistribution please refer to the | |||
* LICENSE file included with these sources. | |||
*/ | |||
package org.apache.fop.pdf; | |||
import java.io.ByteArrayOutputStream; | |||
import java.io.ByteArrayInputStream; | |||
import java.io.InputStream; | |||
import java.io.OutputStream; | |||
import java.io.IOException; | |||
/** | |||
* StreamCache implementation that uses temporary files rather than heap. | |||
*/ | |||
public class InMemoryStreamCache extends StreamCache { | |||
/** | |||
* The current output stream. | |||
*/ | |||
private ByteArrayOutputStream output; | |||
/** | |||
* Creates a new InMemoryStreamCache. | |||
*/ | |||
public InMemoryStreamCache() { | |||
} | |||
/** | |||
* Get the current OutputStream. Do not store it - it may change | |||
* from call to call. | |||
*/ | |||
public OutputStream getOutputStream() throws IOException { | |||
if (output == null) | |||
output = new ByteArrayOutputStream(); | |||
return output; | |||
} | |||
/** | |||
* Filter the cache with the supplied PDFFilter. | |||
*/ | |||
public void applyFilter(PDFFilter filter) throws IOException { | |||
if (output == null) | |||
return; | |||
output.close(); | |||
// make inputstream from copy of outputted bytes | |||
int size = getSize(); | |||
ByteArrayInputStream input = | |||
new ByteArrayInputStream(output.toByteArray()); | |||
// reset output | |||
output.reset(); | |||
// run filter | |||
filter.encode(input, output, size); | |||
input.close(); | |||
output.close(); | |||
} | |||
/** | |||
* Outputs the cached bytes to the given stream. | |||
*/ | |||
public void outputStreamData(OutputStream stream) throws IOException { | |||
if (output == null) | |||
return; | |||
output.writeTo(stream); | |||
} | |||
/** | |||
* Returns the current size of the stream. | |||
*/ | |||
public int getSize() throws IOException { | |||
if (output == null) | |||
return 0; | |||
else | |||
return output.size(); | |||
} | |||
/** | |||
* Closes the cache and frees resources. | |||
*/ | |||
public void close() throws IOException { | |||
if (output != null) { | |||
output.close(); | |||
output = null; | |||
} | |||
} | |||
/** | |||
* Clears and resets the cache. | |||
*/ | |||
public void reset() throws IOException { | |||
if (output != null) { | |||
output.close(); | |||
output = null; | |||
} | |||
} | |||
} |
@@ -11,6 +11,8 @@ | |||
package org.apache.fop.pdf; | |||
import java.io.*; | |||
public abstract class PDFFilter { | |||
/* | |||
* These are no longer needed, but are here as a reminder about what | |||
@@ -60,8 +62,6 @@ public abstract class PDFFilter { | |||
/** | |||
* encode the given data with the filter | |||
*/ | |||
public abstract byte[] encode(byte[] data); | |||
public abstract void encode(InputStream in, OutputStream out, int length) throws IOException; | |||
} |
@@ -11,7 +11,6 @@ import org.apache.fop.datatypes.ColorSpace; | |||
public class PDFICCStream extends PDFStream { | |||
private int origLength; | |||
private int len1, len3; | |||
private byte[] originalData = null; | |||
private ColorSpace cs; | |||
@@ -43,7 +42,7 @@ public class PDFICCStream extends PDFStream { | |||
if (cs.getColorSpace() > 0) | |||
pb.append("/Alternate /").append(cs.getColorSpacePDFString()).append(" "); | |||
pb.append("/Length ").append((_data.size() + 1)).append(" ").append(filterEntry); | |||
pb.append("/Length ").append((_data.getSize() + 1)).append(" ").append(filterEntry); | |||
pb.append(" >>\n"); | |||
byte[] p = pb.toString().getBytes(); | |||
stream.write(p); |
@@ -27,7 +27,7 @@ public class PDFStream extends PDFObject { | |||
/** | |||
* the stream of PDF commands | |||
*/ | |||
protected ByteArrayOutputStream _data; | |||
protected StreamCache _data; | |||
/** | |||
* the filters that should be applied | |||
@@ -41,7 +41,11 @@ public class PDFStream extends PDFObject { | |||
*/ | |||
public PDFStream(int number) { | |||
super(number); | |||
_data = new ByteArrayOutputStream(); | |||
try { | |||
_data = StreamCache.createStreamCache(); | |||
} catch (IOException ex) { | |||
ex.printStackTrace(); | |||
} | |||
_filters = new ArrayList(); | |||
} | |||
@@ -52,7 +56,7 @@ public class PDFStream extends PDFObject { | |||
*/ | |||
public void add(String s) { | |||
try { | |||
_data.write(s.getBytes()); | |||
_data.getOutputStream().write(s.getBytes()); | |||
} catch (IOException ex) { | |||
ex.printStackTrace(); | |||
} | |||
@@ -130,21 +134,21 @@ public class PDFStream extends PDFObject { | |||
int g = (p >> 8) & 0xFF; | |||
int b = (p) & 0xFF; | |||
if (r < 16) { | |||
_data.write('0'); | |||
_data.getOutputStream().write('0'); | |||
} | |||
_data.write(Integer.toHexString(r).getBytes()); | |||
_data.getOutputStream().write(Integer.toHexString(r).getBytes()); | |||
if (g < 16) { | |||
_data.write('0'); | |||
_data.getOutputStream().write('0'); | |||
} | |||
_data.write(Integer.toHexString(g).getBytes()); | |||
_data.getOutputStream().write(Integer.toHexString(g).getBytes()); | |||
if (b < 16) { | |||
_data.write('0'); | |||
_data.getOutputStream().write('0'); | |||
} | |||
_data.write(Integer.toHexString(b).getBytes()); | |||
_data.write(' '); | |||
_data.getOutputStream().write(Integer.toHexString(b).getBytes()); | |||
_data.getOutputStream().write(' '); | |||
} | |||
} | |||
_data.write(">\n".getBytes()); | |||
_data.getOutputStream().write(">\n".getBytes()); | |||
} catch (IOException ex) { | |||
ex.printStackTrace(); | |||
} | |||
@@ -153,15 +157,22 @@ public class PDFStream extends PDFObject { | |||
public void setData(byte[] data) throws IOException { | |||
_data.reset(); | |||
_data.write(data); | |||
_data.getOutputStream().write(data); | |||
} | |||
/* | |||
public byte[] getData() { | |||
return _data.toByteArray(); | |||
} | |||
*/ | |||
public int getDataLength() { | |||
return _data.size(); | |||
try { | |||
return _data.getSize(); | |||
} catch (Exception e) { | |||
e.printStackTrace(); | |||
return 0; | |||
} | |||
} | |||
@@ -188,14 +199,13 @@ public class PDFStream extends PDFObject { | |||
throw new RuntimeException(); | |||
} | |||
// overload the base object method so we don't have to copy | |||
// byte arrays around so much | |||
protected int output(OutputStream stream) throws IOException { | |||
int length = 0; | |||
String filterEntry = applyFilters(); | |||
byte[] p = (this.number + " " + this.generation + " obj\n<< /Length " | |||
+ (_data.size() + 1) + " " + filterEntry | |||
+ (_data.getSize() + 1) + " " + filterEntry | |||
+ " >>\n").getBytes(); | |||
stream.write(p); | |||
@@ -216,8 +226,9 @@ public class PDFStream extends PDFObject { | |||
byte[] p = "stream\n".getBytes(); | |||
stream.write(p); | |||
length += p.length; | |||
_data.writeTo(stream); | |||
length += _data.size(); | |||
_data.outputStreamData(stream); | |||
_data.close(); | |||
length += _data.getSize(); | |||
p = "\nendstream\n".getBytes(); | |||
stream.write(p); | |||
length += p.length; | |||
@@ -243,9 +254,7 @@ public class PDFStream extends PDFObject { | |||
PDFFilter filter = (PDFFilter)_filters.get(count); | |||
// apply the filter encoding if neccessary | |||
if (!filter.isApplied()) { | |||
byte[] tmp = filter.encode(_data.toByteArray()); | |||
_data.reset(); | |||
_data.write(tmp); | |||
_data.applyFilter(filter); | |||
filter.setApplied(true); | |||
} | |||
// place the names in our local vector in reverse order |
@@ -80,7 +80,7 @@ public class PDFT1Stream extends PDFStream { | |||
String filterEntry = applyFilters(); | |||
String preData = new String(this.number + " " + this.generation | |||
+ " obj\n<< /Length " | |||
+ (_data.size() + 1) + " " + filterEntry | |||
+ (_data.getSize() + 1) + " " + filterEntry | |||
+ " " + "/Length1 " + len1 + " /Length2 " | |||
+ (origLength - len3 - len1) | |||
+ " /Length3 " + len3 + " >>\n"); | |||
@@ -101,7 +101,7 @@ public class PDFT1Stream extends PDFStream { | |||
calcLengths(data); | |||
_data.reset(); | |||
// System.out.println("Writing " + size + " bytes of font data"); | |||
_data.write(data, 0, size); | |||
_data.getOutputStream().write(data, 0, size); | |||
} | |||
} |
@@ -23,7 +23,7 @@ public class PDFTTFStream extends PDFStream { | |||
String filterEntry = applyFilters(); | |||
String preData = new String(this.number + " " + this.generation | |||
+ " obj\n<< /Length " | |||
+ (_data.size() + 1) + " " + filterEntry | |||
+ (_data.getSize() + 1) + " " + filterEntry | |||
+ " " + "/Length1 " + origLength | |||
+ " >>\n"); | |||
@@ -41,7 +41,7 @@ public class PDFTTFStream extends PDFStream { | |||
public void setData(byte[] data, int size) throws java.io.IOException { | |||
_data.reset(); | |||
System.out.println("Writing " + size + " bytes of font data"); | |||
_data.write(data, 0, size); | |||
_data.getOutputStream().write(data, 0, size); | |||
} | |||
} |
@@ -0,0 +1,84 @@ | |||
/* | |||
* $Id$ | |||
* Copyright (C) 2001 The Apache Software Foundation. All rights reserved. | |||
* For details on use and redistribution please refer to the | |||
* LICENSE file included with these sources. | |||
*/ | |||
package org.apache.fop.pdf; | |||
import java.io.ByteArrayOutputStream; | |||
import java.io.OutputStream; | |||
import java.io.IOException; | |||
import java.util.ArrayList; | |||
/** | |||
* class used to store the bytes for a PDFStream. It's actually a generic | |||
* cached byte array, along with a factory that returns either an | |||
* in-memory or tempfile based implementation based on the global | |||
* cacheToFile setting. | |||
*/ | |||
public abstract class StreamCache { | |||
/** | |||
* Global setting; controls whether to use tempfiles or not. | |||
*/ | |||
private static boolean cacheToFile = false; | |||
/** | |||
* Change the global cacheToFile flag. | |||
*/ | |||
public static void setCacheToFile(boolean tizit) { | |||
cacheToFile = tizit; | |||
} | |||
/** | |||
* Get the value of the global cacheToFile flag. | |||
*/ | |||
public static boolean getCacheToFile() { | |||
return cacheToFile; | |||
} | |||
/** | |||
* Get the correct implementation (based on cacheToFile) of | |||
* StreamCache. | |||
*/ | |||
public static StreamCache createStreamCache() throws IOException { | |||
if (cacheToFile) | |||
return new TempFileStreamCache(); | |||
else | |||
return new InMemoryStreamCache(); | |||
} | |||
/** | |||
* Get the current OutputStream. Do not store it - it may change | |||
* from call to call. | |||
*/ | |||
public abstract OutputStream getOutputStream() throws IOException; | |||
/** | |||
* Filter the cache with the supplied PDFFilter. | |||
*/ | |||
public abstract void applyFilter(PDFFilter filter) throws IOException; | |||
/** | |||
* Outputs the cached bytes to the given stream. | |||
*/ | |||
public abstract void outputStreamData(OutputStream stream) throws IOException; | |||
/** | |||
* Returns the current size of the stream. | |||
*/ | |||
public abstract int getSize() throws IOException; | |||
/** | |||
* Closes the cache and frees resources. | |||
*/ | |||
public abstract void close() throws IOException; | |||
/** | |||
* Clears and resets the cache. | |||
*/ | |||
public abstract void reset() throws IOException; | |||
} | |||
@@ -0,0 +1,132 @@ | |||
/* | |||
* $Id$ | |||
* Copyright (C) 2002 The Apache Software Foundation. All rights reserved. | |||
* For details on use and redistribution please refer to the | |||
* LICENSE file included with these sources. | |||
*/ | |||
package org.apache.fop.pdf; | |||
import org.apache.fop.util.StreamUtilities; | |||
import java.io.BufferedInputStream; | |||
import java.io.BufferedOutputStream; | |||
import java.io.FileInputStream; | |||
import java.io.FileOutputStream; | |||
import java.io.InputStream; | |||
import java.io.OutputStream; | |||
import java.io.IOException; | |||
import java.io.File; | |||
/** | |||
* StreamCache implementation that uses temporary files rather than heap. | |||
*/ | |||
public class TempFileStreamCache extends StreamCache { | |||
/** | |||
* The current output stream. | |||
*/ | |||
private BufferedOutputStream output; | |||
/** | |||
* The temp file. | |||
*/ | |||
private File tempFile; | |||
/** | |||
* Creates a new TempFileStreamCache. | |||
*/ | |||
public TempFileStreamCache() throws IOException { | |||
tempFile = File.createTempFile("org.apache.fop.pdf.StreamCache-", | |||
".temp"); | |||
tempFile.deleteOnExit(); | |||
} | |||
/** | |||
* Get the current OutputStream. Do not store it - it may change | |||
* from call to call. | |||
*/ | |||
public OutputStream getOutputStream() throws IOException { | |||
if (output == null) | |||
output = new BufferedOutputStream( | |||
new FileOutputStream(tempFile)); | |||
return output; | |||
} | |||
/** | |||
* Filter the cache with the supplied PDFFilter. | |||
*/ | |||
public void applyFilter(PDFFilter filter) throws IOException { | |||
if (output == null) | |||
return; | |||
output.close(); | |||
output = null; | |||
// need a place to put results | |||
File newTempFile = | |||
File.createTempFile("org.apache.fop.pdf.StreamCache-", | |||
".temp"); | |||
newTempFile.deleteOnExit(); | |||
// filter may not be buffered | |||
BufferedInputStream input = | |||
new BufferedInputStream(new FileInputStream(tempFile)); | |||
BufferedOutputStream output = new BufferedOutputStream( | |||
new FileOutputStream(newTempFile)); | |||
filter.encode(input, output, (int) tempFile.length()); | |||
input.close(); | |||
output.close(); | |||
tempFile.delete(); | |||
tempFile = newTempFile; | |||
} | |||
/** | |||
* Outputs the cached bytes to the given stream. | |||
*/ | |||
public void outputStreamData(OutputStream stream) throws IOException { | |||
if (output == null) | |||
return; | |||
output.close(); | |||
output = null; | |||
// don't need a buffer because streamCopy is buffered | |||
FileInputStream input = new FileInputStream(tempFile); | |||
StreamUtilities.streamCopy(input, output); | |||
input.close(); | |||
} | |||
/** | |||
* Returns the current size of the stream. | |||
*/ | |||
public int getSize() throws IOException { | |||
if (output != null) | |||
output.flush(); | |||
return (int) tempFile.length(); | |||
} | |||
/** | |||
* Closes the cache and frees resources. | |||
*/ | |||
public void close() throws IOException { | |||
if (output != null) { | |||
output.close(); | |||
output = null; | |||
} | |||
if (tempFile.exists()) | |||
tempFile.delete(); | |||
} | |||
/** | |||
* Clears and resets the cache. | |||
*/ | |||
public void reset() throws IOException { | |||
if (output != null) { | |||
output.close(); | |||
output = null; | |||
} | |||
if (tempFile.exists()) | |||
tempFile.delete(); | |||
} | |||
} |
@@ -117,7 +117,7 @@ public class AreaTreeBuilder { | |||
PageViewport page = sm.getPage(count, c); | |||
c++; | |||
// save the page to a stream for testing | |||
ObjectOutputStream tempstream = new ObjectOutputStream( | |||
/*ObjectOutputStream tempstream = new ObjectOutputStream( | |||
new BufferedOutputStream( | |||
new FileOutputStream("temp.ser"))); | |||
page.savePage(tempstream); | |||
@@ -129,7 +129,7 @@ public class AreaTreeBuilder { | |||
new BufferedInputStream( | |||
new FileInputStream("temp.ser"))); | |||
page.loadPage(in); | |||
in.close(); | |||
in.close();*/ | |||
rend.renderPage(page); | |||
} | |||
@@ -331,6 +331,7 @@ class TreeLoader { | |||
reg.addBlock(obj); | |||
} | |||
} | |||
reg.setCTM(new CTM()); | |||
return reg; | |||
} | |||
@@ -0,0 +1,147 @@ | |||
/* | |||
* $Id$ | |||
* Copyright (C) 2002 The Apache Software Foundation. All rights reserved. | |||
* For details on use and redistribution please refer to the | |||
* LICENSE file included with these sources. | |||
*/ | |||
package org.apache.fop.util; | |||
import java.io.InputStream; | |||
import java.io.OutputStream; | |||
import java.io.IOException; | |||
import java.io.EOFException; | |||
import java.io.DataInput; | |||
import java.io.DataOutput; | |||
import java.util.zip.CRC32; | |||
/** | |||
* General handy stream i/o methods. | |||
*/ | |||
public class StreamUtilities { | |||
/** | |||
* Size of buffers. Duh. | |||
*/ | |||
public static final int BUFFER_SIZE = 4096; // cuz I like big buffers... | |||
/** | |||
* Binary copies bytes from an input stream to an output stream. | |||
* The process is buffered, so you shouldn't need | |||
* BufferedInput/OutputStreams. Flushes when it's finished, but does | |||
* not close either stream. Returns the number of bytes copied. | |||
*/ | |||
public static long streamCopy(InputStream source, | |||
OutputStream sink) throws IOException { | |||
// set table | |||
byte[] buffer = new byte[BUFFER_SIZE]; | |||
long total = 0; | |||
// trough | |||
int scoop; | |||
while ((scoop = source.read(buffer)) >= 0) { | |||
if (scoop == 0) | |||
System.out.println("zero scoop!"); | |||
sink.write(buffer, 0, scoop); | |||
total += scoop; | |||
} | |||
// do dishes | |||
sink.flush(); | |||
return total; | |||
} | |||
/** | |||
* Binary copies up to the given number of bytes from an input | |||
* stream to an output stream. The process is buffered, so you | |||
* shouldn't need BufferedInput/OutputStreams. | |||
* Flushes when it's finished, but does not close either stream. | |||
* Throws an EOFExeption if there aren't enough bytes available to | |||
* transfer the requested amount. | |||
* Returns the total number of bytes copied. | |||
*/ | |||
public static long streamCopy(InputStream source, | |||
OutputStream sink, int howMany) throws IOException { | |||
// set table | |||
byte[] buffer = new byte[BUFFER_SIZE]; | |||
int left = howMany; | |||
// trough | |||
int scoop; | |||
while (left > 0) { | |||
scoop = source.read(buffer, 0, Math.min(BUFFER_SIZE, left)); | |||
if (scoop < 0) | |||
throw new EOFException( | |||
"Not enough bytes to feed you in IOLib.streamCopy(source, sink, howMany); you asked for " + | |||
howMany + " and I only have " + (howMany - left)); | |||
sink.write(buffer, 0, scoop); | |||
left -= scoop; | |||
} | |||
// do dishes | |||
sink.flush(); | |||
return howMany; | |||
} | |||
/** | |||
* Binary copies up to the given number of bytes from an input | |||
* stream to an output stream. The process is buffered, so you | |||
* shouldn't need BufferedInput/OutputStreams. | |||
* Flushes when it's finished, but does not close either stream. | |||
* Throws an EOFExeption if there aren't enough bytes available | |||
* to transfer the requested amount. | |||
* Returns the checksum of the bytes copied. | |||
*/ | |||
public static long streamCopyWithChecksum(InputStream source, | |||
OutputStream sink, int howMany) throws IOException { | |||
// set table | |||
byte[] buffer = new byte[BUFFER_SIZE]; | |||
int left = howMany; | |||
CRC32 checksummer = new CRC32(); | |||
// trough | |||
int scoop; | |||
while (left > 0) { | |||
scoop = source.read(buffer, 0, Math.min(BUFFER_SIZE, left)); | |||
if (scoop < 0) | |||
throw new EOFException("Not enough bytes to feed you in IOLib.streamCopy(source, sink, howMany)"); | |||
checksummer.update(buffer, 0, scoop); | |||
sink.write(buffer, 0, scoop); | |||
left -= scoop; | |||
} | |||
// do dishes | |||
sink.flush(); | |||
return checksummer.getValue(); | |||
} | |||
/** | |||
* Binary copies up to the given number of bytes from a DataInput | |||
* object to an DataOutput object. The process is buffered. Since | |||
* DataOutput doesn't support closing or flushing, it does neither. | |||
* Returns the total number of bytes copied. | |||
*/ | |||
public static long dataCopy(DataInput source, DataOutput sink, | |||
int howMany) throws IOException { | |||
// set table | |||
byte[] buffer = new byte[BUFFER_SIZE]; | |||
int left = howMany; | |||
// trough | |||
int scoop; | |||
while (left > 0) { | |||
scoop = Math.min(BUFFER_SIZE, left); | |||
source.readFully(buffer, 0, scoop); | |||
sink.write(buffer, 0, scoop); | |||
left -= scoop; | |||
} | |||
// do dishes | |||
return howMany; | |||
} | |||
} |