X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=src%2Fnet%2Fpterodactylus%2Ffcp%2FFcpUtils.java;h=095708366bec6b54823f8daa6ce0ec105355d771;hb=a655177a4605236e866ac7e0ce32f7cb5289cbc4;hp=cf8b8d346452cb6a5d9c4c4074593d7c3b1dbd03;hpb=64c2c9bd494f3ea9d1ae84f8d86827dea025bee6;p=jFCPlib.git diff --git a/src/net/pterodactylus/fcp/FcpUtils.java b/src/net/pterodactylus/fcp/FcpUtils.java index cf8b8d3..0957083 100644 --- a/src/net/pterodactylus/fcp/FcpUtils.java +++ b/src/net/pterodactylus/fcp/FcpUtils.java @@ -1,6 +1,5 @@ /* - * jSite2 - FcpUtils.java - - * Copyright © 2008 David Roden + * jFCPlib - FcpUtils.java - Copyright © 2008 David Roden * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,8 +18,13 @@ package net.pterodactylus.fcp; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.EOFException; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -30,8 +34,8 @@ import java.util.concurrent.atomic.AtomicLong; /** * Helper class with utility methods for the FCP protocol. - * - * @author David Roden + * + * @author David ‘Bombe’ Roden <bombe@freenetproject.org> */ public class FcpUtils { @@ -40,7 +44,7 @@ public class FcpUtils { /** * Returns a unique identifier. - * + * * @return A unique identifier */ public static String getUniqueIdentifier() { @@ -49,7 +53,7 @@ public class FcpUtils { /** * Parses an integer field, separated by ‘;’ and returns the parsed values. - * + * * @param field * The field to parse * @return An array with the parsed values @@ -70,14 +74,14 @@ public class FcpUtils { /** * Encodes the given integer array into a string, separating the values by * ‘;’. - * + * * @param values * The values to encode * @return The encoded values */ public static String encodeMultiIntegerField(int[] values) { StringBuilder encodedField = new StringBuilder(); - for (int value: values) { + for (int value : values) { if (encodedField.length() > 0) { encodedField.append(';'); } @@ -89,14 +93,14 @@ public class FcpUtils { /** * Encodes the given string array into a string, separating the values by * ‘;’. - * + * * @param values * The values to encode * @return The encoded values */ public static String encodeMultiStringField(String[] values) { StringBuilder encodedField = new StringBuilder(); - for (String value: values) { + for (String value : values) { if (encodedField.length() > 0) { encodedField.append(';'); } @@ -106,9 +110,9 @@ public class FcpUtils { } /** - * Tries to parse the given string into an int, returning -1 - * if the string can not be parsed. - * + * Tries to parse the given string into an int, returning -1 if + * the string can not be parsed. + * * @param value * The string to parse * @return The parsed int, or -1 @@ -120,7 +124,7 @@ public class FcpUtils { /** * Tries to parse the given string into an int, returning * defaultValue if the string can not be parsed. - * + * * @param value * The string to parse * @param defaultValue @@ -138,7 +142,7 @@ public class FcpUtils { /** * Tries to parse the given string into an long, returning -1 * if the string can not be parsed. - * + * * @param value * The string to parse * @return The parsed long, or -1 @@ -150,7 +154,7 @@ public class FcpUtils { /** * Tries to parse the given string into an long, returning * defaultValue if the string can not be parsed. - * + * * @param value * The string to parse * @param defaultValue @@ -167,7 +171,7 @@ public class FcpUtils { /** * Closes the given socket. - * + * * @param socket * The socket to close */ @@ -183,7 +187,7 @@ public class FcpUtils { /** * Closes the given Closeable. - * + * * @param closeable * The Closeable to close */ @@ -199,9 +203,9 @@ public class FcpUtils { /** * Copies as many bytes as possible (i.e. until {@link InputStream#read()} - * returns -1) from the source input stream to the - * destination output stream. - * + * returns -1) from the source input stream to the destination + * output stream. + * * @param source * The input stream to read from * @param destination @@ -215,11 +219,11 @@ public class FcpUtils { /** * Copies length bytes from the source input stream to the - * destination output stream. If length is -1 - * as much bytes as possible will be copied (i.e. until + * destination output stream. If length is -1 as + * much bytes as possible will be copied (i.e. until * {@link InputStream#read()} returns -1 to signal the end of * the stream). - * + * * @param source * The input stream to read from * @param destination @@ -235,11 +239,11 @@ public class FcpUtils { /** * Copies length bytes from the source input stream to the - * destination output stream. If length is -1 - * as much bytes as possible will be copied (i.e. until + * destination output stream. If length is -1 as + * much bytes as possible will be copied (i.e. until * {@link InputStream#read()} returns -1 to signal the end of * the stream). - * + * * @param source * The input stream to read from * @param destination @@ -268,4 +272,198 @@ public class FcpUtils { } } + /** + * This input stream stores the content of another input stream either in a + * file or in memory, depending on the length of the input stream. + * + * @author David ‘Bombe’ Roden <bombe@freenetproject.org> + */ + public static class TempInputStream extends InputStream { + + /** The default maximum lenght for in-memory storage. */ + public static final long MAX_LENGTH_MEMORY = 65536; + + /** The temporary file to read from. */ + private final File tempFile; + + /** The input stream that reads from the file. */ + private final InputStream fileInputStream; + + /** The input stream that reads from memory. */ + private final InputStream memoryInputStream; + + /** + * Creates a new temporary input stream that stores the given input + * stream in a temporary file. + * + * @param originalInputStream + * The original input stream + * @throws IOException + * if an I/O error occurs + */ + public TempInputStream(InputStream originalInputStream) throws IOException { + this(originalInputStream, -1); + } + + /** + * Creates a new temporary input stream that stores the given input + * stream in memory if it is shorter than {@link #MAX_LENGTH_MEMORY}, + * otherwise it is stored in a file. + * + * @param originalInputStream + * The original input stream + * @param length + * The length of the input stream + * @throws IOException + * if an I/O error occurs + */ + public TempInputStream(InputStream originalInputStream, long length) throws IOException { + this(originalInputStream, length, MAX_LENGTH_MEMORY); + } + + /** + * Creates a new temporary input stream that stores the given input + * stream in memory if it is shorter than maxMemoryLength, + * otherwise it is stored in a file. + * + * @param originalInputStream + * The original input stream + * @param length + * The length of the input stream + * @param maxMemoryLength + * The maximum length to store in memory + * @throws IOException + * if an I/O error occurs + */ + public TempInputStream(InputStream originalInputStream, long length, long maxMemoryLength) throws IOException { + if ((length > -1) && (length <= maxMemoryLength)) { + ByteArrayOutputStream memoryOutputStream = new ByteArrayOutputStream((int) length); + try { + FcpUtils.copy(originalInputStream, memoryOutputStream, length, (int) length); + } finally { + memoryOutputStream.close(); + } + tempFile = null; + fileInputStream = null; + memoryInputStream = new ByteArrayInputStream(memoryOutputStream.toByteArray()); + } else { + tempFile = File.createTempFile("temp-", ".bin"); + tempFile.deleteOnExit(); + FileOutputStream fileOutputStream = null; + try { + fileOutputStream = new FileOutputStream(tempFile); + FcpUtils.copy(originalInputStream, fileOutputStream); + fileInputStream = new FileInputStream(tempFile); + } finally { + FcpUtils.close(fileOutputStream); + } + memoryInputStream = null; + } + } + + /** + * {@inheritDoc} + */ + @Override + public int available() throws IOException { + if (memoryInputStream != null) { + return memoryInputStream.available(); + } + return fileInputStream.available(); + } + + /** + * {@inheritDoc} + */ + @Override + public void close() throws IOException { + if (memoryInputStream != null) { + memoryInputStream.close(); + return; + } + tempFile.delete(); + fileInputStream.close(); + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized void mark(int readlimit) { + if (memoryInputStream != null) { + memoryInputStream.mark(readlimit); + return; + } + fileInputStream.mark(readlimit); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean markSupported() { + if (memoryInputStream != null) { + return memoryInputStream.markSupported(); + } + return fileInputStream.markSupported(); + } + + /** + * {@inheritDoc} + */ + @Override + public int read() throws IOException { + if (memoryInputStream != null) { + return memoryInputStream.read(); + } + return fileInputStream.read(); + } + + /** + * {@inheritDoc} + */ + @Override + public int read(byte[] b) throws IOException { + if (memoryInputStream != null) { + return memoryInputStream.read(b); + } + return fileInputStream.read(b); + } + + /** + * {@inheritDoc} + */ + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (memoryInputStream != null) { + return memoryInputStream.read(b, off, len); + } + return fileInputStream.read(b, off, len); + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized void reset() throws IOException { + if (memoryInputStream != null) { + memoryInputStream.reset(); + return; + } + fileInputStream.reset(); + } + + /** + * {@inheritDoc} + */ + @Override + public long skip(long n) throws IOException { + if (memoryInputStream != null) { + return memoryInputStream.skip(n); + } + return fileInputStream.skip(n); + } + + } + }