1 package be
.nikiroo
.utils
.streams
;
3 import java
.io
.IOException
;
4 import java
.io
.InputStream
;
6 import be
.nikiroo
.utils
.StringUtils
;
9 * This {@link InputStream} will change some of its content by replacing it with
14 public class ReplaceInputStream
extends BufferedInputStream
{
16 * The minimum size of the internal buffer (could be more if at least one of
17 * the 'FROM' bytes arrays is > 2048 bytes — in that case the
18 * buffer will be twice the largest size of the 'FROM' bytes arrays).
20 * This is a different buffer than the one from the inherited class.
22 static private final int MIN_BUFFER_SIZE
= 4096;
24 private byte[][] froms
;
26 private int maxFromSize
;
27 private int maxToSize
;
29 private byte[] source
;
34 * Create a {@link ReplaceInputStream} that will replace <tt>from</tt> with
38 * the under-laying {@link InputStream}
40 * the {@link String} to replace
42 * the {@link String} to replace with
44 public ReplaceInputStream(InputStream in
, String from
, String to
) {
45 this(in
, StringUtils
.getBytes(from
), StringUtils
.getBytes(to
));
49 * Create a {@link ReplaceInputStream} that will replace <tt>from</tt> with
53 * the under-laying {@link InputStream}
55 * the value to replace
57 * the value to replace with
59 public ReplaceInputStream(InputStream in
, byte[] from
, byte[] to
) {
60 this(in
, new byte[][] { from
}, new byte[][] { to
});
64 * Create a {@link ReplaceInputStream} that will replace all <tt>froms</tt>
67 * Note that they will be replaced in order, and that for each <tt>from</tt>
68 * a <tt>to</tt> must correspond.
71 * the under-laying {@link InputStream}
73 * the values to replace
75 * the values to replace with
77 public ReplaceInputStream(InputStream in
, String
[] froms
, String
[] tos
) {
78 this(in
, StreamUtils
.getBytes(froms
), StreamUtils
.getBytes(tos
));
82 * Create a {@link ReplaceInputStream} that will replace all <tt>froms</tt>
85 * Note that they will be replaced in order, and that for each <tt>from</tt>
86 * a <tt>to</tt> must correspond.
89 * the under-laying {@link InputStream}
91 * the values to replace
93 * the values to replace with
95 public ReplaceInputStream(InputStream in
, byte[][] froms
, byte[][] tos
) {
98 if (froms
.length
!= tos
.length
) {
99 throw new IllegalArgumentException(
100 "For replacing, each FROM must have a corresponding TO");
107 for (int i
= 0; i
< froms
.length
; i
++) {
108 maxFromSize
= Math
.max(maxFromSize
, froms
[i
].length
);
112 for (int i
= 0; i
< tos
.length
; i
++) {
113 maxToSize
= Math
.max(maxToSize
, tos
[i
].length
);
116 // We need at least maxFromSize so we can iterate and replace
117 source
= new byte[Math
.max(2 * maxFromSize
, MIN_BUFFER_SIZE
)];
123 protected int read(InputStream in
, byte[] buffer
, int off
, int len
)
125 if (len
< maxToSize
|| source
.length
< maxToSize
* 2) {
126 throw new IOException(
127 "An underlaying buffer is too small for these replace values");
130 // We need at least one byte of data to process
131 if (available() < Math
.max(maxFromSize
, 1) && !eof
) {
133 slen
= in
.read(source
);
136 // Note: very simple, not efficient implementation; sorry.
138 while (spos
< slen
&& count
< len
- maxToSize
) {
139 boolean replaced
= false;
140 for (int i
= 0; i
< froms
.length
; i
++) {
141 if (froms
[i
] != null && froms
[i
].length
> 0
142 && StreamUtils
.startsWith(froms
[i
], source
, spos
, slen
)) {
143 if (tos
[i
] != null && tos
[i
].length
> 0) {
144 System
.arraycopy(tos
[i
], 0, buffer
, off
+ spos
,
146 count
+= tos
[i
].length
;
149 spos
+= froms
[i
].length
;
156 buffer
[off
+ count
++] = source
[spos
++];