fix limit in replace for BufferedInputStream
[fanfix.git] / src / be / nikiroo / utils / streams / ReplaceInputStream.java
index eea3a1ab9b74b42158d5b40e565b59c839cb690a..ae576e25e7a4833e9ce8f4bea25616ff018eca52 100644 (file)
@@ -3,6 +3,8 @@ package be.nikiroo.utils.streams;
 import java.io.IOException;
 import java.io.InputStream;
 
+import be.nikiroo.utils.StringUtils;
+
 /**
  * This {@link InputStream} will change some of its content by replacing it with
  * something else.
@@ -10,8 +12,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 > 2048 bytes — 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;
@@ -30,7 +42,7 @@ public class ReplaceInputStream extends BufferedInputStream {
         *            the {@link String} to replace with
         */
        public ReplaceInputStream(InputStream in, String from, String to) {
-               this(in, StreamUtils.bytes(from), StreamUtils.bytes(to));
+               this(in, StringUtils.getBytes(from), StringUtils.getBytes(to));
        }
 
        /**
@@ -63,7 +75,7 @@ public class ReplaceInputStream extends BufferedInputStream {
         *            the values to replace with
         */
        public ReplaceInputStream(InputStream in, String[] froms, String[] tos) {
-               this(in, StreamUtils.bytes(froms), StreamUtils.bytes(tos));
+               this(in, StreamUtils.getBytes(froms), StreamUtils.getBytes(tos));
        }
 
        /**
@@ -91,39 +103,50 @@ 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 * Math.max(maxToSize, maxFromSize),
+                               MIN_BUFFER_SIZE)];
                spos = 0;
                slen = 0;
        }
 
        @Override
-       protected int read(InputStream in, byte[] buffer) throws IOException {
-               if (buffer.length < maxToSize || source.length < maxToSize * 2) {
+       protected int read(InputStream in, byte[] buffer, int off, int len)
+                       throws IOException {
+               if (len < maxToSize || source.length < maxToSize * 2) {
                        throw new IOException(
                                        "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 < buffer.length - maxToSize) {
+               while (spos < slen && count < len - maxToSize) {
                        boolean replaced = false;
                        for (int i = 0; i < froms.length; i++) {
                                if (froms[i] != null && froms[i].length > 0
                                                && StreamUtils.startsWith(froms[i], source, spos, slen)) {
                                        if (tos[i] != null && tos[i].length > 0) {
-                                               System.arraycopy(tos[i], 0, buffer, spos, tos[i].length);
+                                               System.arraycopy(tos[i], 0, buffer, off + count,
+                                                               tos[i].length);
                                                count += tos[i].length;
                                        }
-
+                                       
                                        spos += froms[i].length;
                                        replaced = true;
                                        break;
@@ -131,7 +154,7 @@ public class ReplaceInputStream extends BufferedInputStream {
                        }
 
                        if (!replaced) {
-                               buffer[count++] = source[spos++];
+                               buffer[off + count++] = source[spos++];
                        }
                }