code cleanup, fix for ReplaceInputStream
authorNiki Roo <niki@nikiroo.be>
Mon, 29 Apr 2019 18:10:07 +0000 (20:10 +0200)
committerNiki Roo <niki@nikiroo.be>
Mon, 29 Apr 2019 18:10:07 +0000 (20:10 +0200)
src/be/nikiroo/utils/Cache.java
src/be/nikiroo/utils/IOUtils.java
src/be/nikiroo/utils/Image.java
src/be/nikiroo/utils/streams/Base64.java
src/be/nikiroo/utils/streams/Base64InputStream.java
src/be/nikiroo/utils/streams/BufferedInputStream.java
src/be/nikiroo/utils/streams/MarkableFileInputStream.java
src/be/nikiroo/utils/streams/NextableInputStream.java
src/be/nikiroo/utils/streams/ReplaceInputStream.java
src/be/nikiroo/utils/streams/ReplaceOutputStream.java

index cf8a780ef9ae49f99b5536a5d549e5522a01837b..ff2859eb44403062a5186abd78aa0233316a4926 100644 (file)
@@ -1,7 +1,6 @@
 package be.nikiroo.utils;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
@@ -265,7 +264,7 @@ public class Cache {
                if (cached.exists() && cached.isFile()
                                && (allowTooOld || !isOld(cached, stable))) {
                        try {
-                               return new MarkableFileInputStream(new FileInputStream(cached));
+                               return new MarkableFileInputStream(cached);
                        } catch (FileNotFoundException e) {
                                return null;
                        }
index 9ab638af06e1486122de1c059abec3eb5b0a4980..fa18d0de5c868f411d2d7da88e2cf39fd0e47f23 100644 (file)
@@ -410,19 +410,11 @@ public class IOUtils {
                        write(in, tmp);
                        in.close();
 
-                       final FileInputStream fis = new FileInputStream(tmp);
-                       return new MarkableFileInputStream(fis) {
+                       return new MarkableFileInputStream(tmp) {
                                @Override
                                public void close() throws IOException {
                                        try {
-                                               try {
-                                                       super.close();
-                                               } finally {
-                                                       try {
-                                                               fis.close();
-                                                       } catch (IOException e) {
-                                                       }
-                                               }
+                                               super.close();
                                        } finally {
                                                tmp.delete();
                                        }
index f2b94991417ff922dba3a8c00713fe7202912657..58b1f5aeac05f71370365ac9c3a562f70f722797 100644 (file)
@@ -3,7 +3,6 @@ package be.nikiroo.utils;
 import java.io.ByteArrayInputStream;
 import java.io.Closeable;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 
@@ -81,7 +80,7 @@ public class Image implements Closeable {
         *             in case of I/O error
         */
        public InputStream newInputStream() throws IOException {
-               return new MarkableFileInputStream(new FileInputStream(data));
+               return new MarkableFileInputStream(data);
        }
 
        /**
index a4f1240aa6603109cf6fb14f17862dafaed59678..76b4be49f731e9b2ee1387b0a3190fe9555dbd34 100644 (file)
@@ -260,7 +260,8 @@ class Base64 {
          * @return an overestimate for the number of bytes {@code
          * len} bytes could decode to.
          */
-        public int maxOutputSize(int len) {
+        @Override
+               public int maxOutputSize(int len) {
             return len * 3/4 + 10;
         }
 
@@ -270,7 +271,8 @@ class Base64 {
          * @return true if the state machine is still healthy.  false if
          *         bad base-64 data has been detected in the input stream.
          */
-        public boolean process(byte[] input, int offset, int len, boolean finish) {
+        @Override
+               public boolean process(byte[] input, int offset, int len, boolean finish) {
             if (this.state == 6) return false;
 
             int p = offset;
@@ -606,11 +608,13 @@ class Base64 {
          * @return an overestimate for the number of bytes {@code
          * len} bytes could encode to.
          */
-        public int maxOutputSize(int len) {
+        @Override
+               public int maxOutputSize(int len) {
             return len * 8/5 + 10;
         }
 
-        public boolean process(byte[] input, int offset, int len, boolean finish) {
+        @Override
+               public boolean process(byte[] input, int offset, int len, boolean finish) {
             // Using local variables makes the encoder about 9% faster.
             final byte[] alphabet = this.alphabet;
             final byte[] output = this.output;
@@ -638,7 +642,7 @@ class Base64 {
                             ((input[p++] & 0xff) << 8) |
                             (input[p++] & 0xff);
                         tailLen = 0;
-                    };
+                    }
                     break;
 
                 case 2:
index b2357419696c67bf54d1393b92af6e044d72c039..a3afaefc66191d1bdb5f742d609f1af9ce5eabf5 100644 (file)
@@ -70,28 +70,36 @@ public class Base64InputStream extends FilterInputStream {
         outputEnd = 0;
     }
 
-    public boolean markSupported() {
+    @Override
+       public boolean markSupported() {
         return false;
     }
 
-    public void mark(int readlimit) {
+    @SuppressWarnings("sync-override")
+       @Override
+       public void mark(int readlimit) {
         throw new UnsupportedOperationException();
     }
 
-    public void reset() {
+    @SuppressWarnings("sync-override")
+       @Override
+       public void reset() {
         throw new UnsupportedOperationException();
     }
 
-    public void close() throws IOException {
+    @Override
+       public void close() throws IOException {
         in.close();
         inputBuffer = null;
     }
 
-    public int available() {
+    @Override
+       public int available() {
         return outputEnd - outputStart;
     }
 
-    public long skip(long n) throws IOException {
+    @Override
+       public long skip(long n) throws IOException {
         if (outputStart >= outputEnd) {
             refill();
         }
@@ -103,18 +111,20 @@ public class Base64InputStream extends FilterInputStream {
         return bytes;
     }
 
-    public int read() throws IOException {
+    @Override
+       public int read() throws IOException {
         if (outputStart >= outputEnd) {
             refill();
         }
         if (outputStart >= outputEnd) {
             return -1;
-        } else {
-            return coder.output[outputStart++] & 0xff;
         }
+        
+        return coder.output[outputStart++] & 0xff;
     }
 
-    public int read(byte[] b, int off, int len) throws IOException {
+    @Override
+       public int read(byte[] b, int off, int len) throws IOException {
         if (outputStart >= outputEnd) {
             refill();
         }
index 397f6fcf9b22f414631cddb899ab38a3b38f3fa1..42f0d9d24c123be0fad89cce35f43bb9b5831855 100644 (file)
@@ -14,13 +14,22 @@ import java.util.Arrays;
  * @author niki
  */
 public class BufferedInputStream extends InputStream {
+       /**
+        * The size of the internal buffer (can be different if you pass your own
+        * buffer, of course).
+        * <p>
+        * A second buffer of twice the size can sometimes be created as needed for
+        * the {@link BufferedInputStream#startsWith(byte[])} search operation.
+        */
+       static private final int BUFFER_SIZE = 4096;
+
        /** The current position in the buffer. */
        protected int start;
        /** The index of the last usable position of the buffer. */
        protected int stop;
        /** The buffer itself. */
        protected byte[] buffer;
-       /** An End-Of-File (or buffer, here) marker. */
+       /** An End-Of-File (or {@link InputStream}, here) marker. */
        protected boolean eof;
 
        private boolean closed;
@@ -45,7 +54,7 @@ public class BufferedInputStream extends InputStream {
        public BufferedInputStream(InputStream in) {
                this.in = in;
 
-               this.buffer = new byte[4096];
+               this.buffer = new byte[BUFFER_SIZE];
                this.originalBuffer = this.buffer;
                this.start = 0;
                this.stop = 0;
index dab4cdc45a536f993f8e6924d89ef4fdd5780e32..7622b24f5af52e6234f446f88b0500d88f31eb3f 100644 (file)
@@ -1,6 +1,8 @@
 package be.nikiroo.utils.streams;
 
+import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.FilterInputStream;
 import java.io.IOException;
 import java.nio.channels.FileChannel;
@@ -15,6 +17,19 @@ public class MarkableFileInputStream extends FilterInputStream {
        private FileChannel channel;
        private long mark = 0;
 
+       /**
+        * Create a new {@link MarkableFileInputStream} from this file.
+        * 
+        * @param file
+        *            the {@link File} to wrap
+        * 
+        * @throws FileNotFoundException
+        *             if the {@link File} cannot be found
+        */
+       public MarkableFileInputStream(File file) throws FileNotFoundException {
+               this(new FileInputStream(file));
+       }
+
        /**
         * Create a new {@link MarkableFileInputStream} from this stream.
         * 
index 62156e3e4285f53bb1d0e72e4be95f0f91ea3452..550aa24f459f2fe0fc1c28fe3efa80f606a59a88 100644 (file)
@@ -246,7 +246,13 @@ public class NextableInputStream extends BufferedInputStream {
                return true;
        }
 
-       public String DEBUG() {
+       /**
+        * Display a DEBUG {@link String} representation of this object.
+        * <p>
+        * Do <b>not</b> use for release code.
+        */
+       @Override
+       public String toString() {
                String data = "";
                if (stop > 0) {
                        try {
index b2187af09ce189dae52105733c10559f0db4aff0..5332e72d11651cb7da0588e817bbb10310a39449 100644 (file)
@@ -10,8 +10,18 @@ import java.io.InputStream;
  * @author niki
  */
 public class ReplaceInputStream extends BufferedInputStream {
+       /**
+        * The minimum size of the internal buffer (could be more if at least one of
+        * the 'FROM' bytes arrays is &gt; 2048 bytes &mdash; in that case the
+        * buffer will be twice the largest size of the 'FROM' bytes arrays).
+        * <p>
+        * This is a different buffer than the one from the inherited class.
+        */
+       static private final int MIN_BUFFER_SIZE = 4096;
+
        private byte[][] froms;
        private byte[][] tos;
+       private int maxFromSize;
        private int maxToSize;
 
        private byte[] source;
@@ -91,11 +101,18 @@ public class ReplaceInputStream extends BufferedInputStream {
                this.froms = froms;
                this.tos = tos;
 
+               maxFromSize = 0;
+               for (int i = 0; i < froms.length; i++) {
+                       maxFromSize = Math.max(maxFromSize, froms[i].length);
+               }
+
+               maxToSize = 0;
                for (int i = 0; i < tos.length; i++) {
                        maxToSize = Math.max(maxToSize, tos[i].length);
                }
 
-               source = new byte[4096];
+               // We need at least maxFromSize so we can iterate and replace
+               source = new byte[Math.max(2 * maxFromSize, MIN_BUFFER_SIZE)];
                spos = 0;
                slen = 0;
        }
@@ -108,12 +125,13 @@ public class ReplaceInputStream extends BufferedInputStream {
                                        "An underlaying buffer is too small for these replace values");
                }
 
-               if (spos >= slen) {
+               // We need at least one byte of data to process
+               if (available() < Math.max(maxFromSize, 1) && !eof) {
                        spos = 0;
                        slen = in.read(source);
                }
 
-               // Note: very simple, not efficient implementation, sorry.
+               // Note: very simple, not efficient implementation; sorry.
                int count = 0;
                while (spos < slen && count < len - maxToSize) {
                        boolean replaced = false;
index ff871eb815d4b5a8672cfd746449a09524684968..e7e6c9f5a7c03456902e471864722af00478de48 100644 (file)
@@ -88,9 +88,30 @@ public class ReplaceOutputStream extends BufferedOutputStream {
                this.tos = tos;
        }
 
+       /**
+        * Flush the {@link BufferedOutputStream}, write the current buffered data
+        * to (and optionally also flush) the under-laying stream.
+        * <p>
+        * If {@link BufferedOutputStream#bypassFlush} is false, all writes to the
+        * under-laying stream are done in this method.
+        * <p>
+        * This can be used if you want to write some data in the under-laying
+        * stream yourself (in that case, flush this {@link BufferedOutputStream}
+        * with or without flushing the under-laying stream, then you can write to
+        * the under-laying stream).
+        * <p>
+        * <b>But be careful!</b> If a replacement could be done with the end o the
+        * currently buffered data and the start of the data to come, we obviously
+        * will not be able to do it.
+        * 
+        * @param includingSubStream
+        *            also flush the under-laying stream
+        * @throws IOException
+        *             in case of I/O error
+        */
        @Override
        public void flush(boolean includingSubStream) throws IOException {
-               // Note: very simple, not efficient implementation, sorry.
+               // Note: very simple, not efficient implementation; sorry.
                while (start < stop) {
                        boolean replaced = false;
                        for (int i = 0; i < froms.length; i++) {