More whitespace fixes.
[jFCPlib.git] / src / net / pterodactylus / fcp / FcpUtils.java
index cf8b8d3..0957083 100644 (file)
@@ -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
 
 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 <a href="mailto:dr@ina-germany.de">David Roden</a>
+ *
+ * @author David ‘Bombe’ Roden &lt;bombe@freenetproject.org&gt;
  */
 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 <code>-1</code>
-        * if the string can not be parsed.
-        * 
+        * Tries to parse the given string into an int, returning <code>-1</code> if
+        * the string can not be parsed.
+        *
         * @param value
         *            The string to parse
         * @return The parsed int, or <code>-1</code>
@@ -120,7 +124,7 @@ public class FcpUtils {
        /**
         * Tries to parse the given string into an int, returning
         * <code>defaultValue</code> 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 <code>-1</code>
         * if the string can not be parsed.
-        * 
+        *
         * @param value
         *            The string to parse
         * @return The parsed long, or <code>-1</code>
@@ -150,7 +154,7 @@ public class FcpUtils {
        /**
         * Tries to parse the given string into an long, returning
         * <code>defaultValue</code> 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 <code>-1</code>) from the source input stream to the
-        * destination output stream.
-        * 
+        * returns <code>-1</code>) 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 <code>length</code> bytes from the source input stream to the
-        * destination output stream. If <code>length</code> is <code>-1</code>
-        * as much bytes as possible will be copied (i.e. until
+        * destination output stream. If <code>length</code> is <code>-1</code> as
+        * much bytes as possible will be copied (i.e. until
         * {@link InputStream#read()} returns <code>-1</code> 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 <code>length</code> bytes from the source input stream to the
-        * destination output stream. If <code>length</code> is <code>-1</code>
-        * as much bytes as possible will be copied (i.e. until
+        * destination output stream. If <code>length</code> is <code>-1</code> as
+        * much bytes as possible will be copied (i.e. until
         * {@link InputStream#read()} returns <code>-1</code> 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 &lt;bombe@freenetproject.org&gt;
+        */
+       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 <code>maxMemoryLength</code>,
+                * 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);
+               }
+
+       }
+
 }