Commit | Line | Data |
---|---|---|
8e76f6ab | 1 | package be.nikiroo.utils.streams; |
6ef54b36 NR |
2 | |
3 | import java.io.IOException; | |
4 | import java.io.InputStream; | |
6ef54b36 | 5 | |
876dbf8b | 6 | /** |
c8ce09c4 NR |
7 | * This {@link InputStream} will change some of its content by replacing it with |
8 | * something else. | |
876dbf8b NR |
9 | * |
10 | * @author niki | |
11 | */ | |
6ef54b36 | 12 | public class ReplaceInputStream extends BufferedInputStream { |
627f866e NR |
13 | private byte[][] froms; |
14 | private byte[][] tos; | |
15 | private int maxToSize; | |
6ef54b36 NR |
16 | |
17 | private byte[] source; | |
18 | private int spos; | |
19 | private int slen; | |
20 | ||
876dbf8b NR |
21 | /** |
22 | * Create a {@link ReplaceInputStream} that will replace <tt>from</tt> with | |
23 | * <tt>to</tt>. | |
24 | * | |
25 | * @param in | |
26 | * the under-laying {@link InputStream} | |
27 | * @param from | |
28 | * the {@link String} to replace | |
29 | * @param to | |
30 | * the {@link String} to replace with | |
31 | */ | |
6ef54b36 | 32 | public ReplaceInputStream(InputStream in, String from, String to) { |
c8ce09c4 | 33 | this(in, StreamUtils.bytes(from), StreamUtils.bytes(to)); |
6ef54b36 NR |
34 | } |
35 | ||
876dbf8b NR |
36 | /** |
37 | * Create a {@link ReplaceInputStream} that will replace <tt>from</tt> with | |
38 | * <tt>to</tt>. | |
39 | * | |
40 | * @param in | |
41 | * the under-laying {@link InputStream} | |
42 | * @param from | |
43 | * the value to replace | |
44 | * @param to | |
45 | * the value to replace with | |
46 | */ | |
6ef54b36 | 47 | public ReplaceInputStream(InputStream in, byte[] from, byte[] to) { |
627f866e NR |
48 | this(in, new byte[][] { from }, new byte[][] { to }); |
49 | } | |
50 | ||
51 | /** | |
52 | * Create a {@link ReplaceInputStream} that will replace all <tt>froms</tt> | |
53 | * with <tt>tos</tt>. | |
54 | * <p> | |
55 | * Note that they will be replaced in order, and that for each <tt>from</tt> | |
56 | * a <tt>to</tt> must correspond. | |
57 | * | |
58 | * @param in | |
59 | * the under-laying {@link InputStream} | |
60 | * @param froms | |
61 | * the values to replace | |
62 | * @param tos | |
63 | * the values to replace with | |
64 | */ | |
65 | public ReplaceInputStream(InputStream in, String[] froms, String[] tos) { | |
66 | this(in, StreamUtils.bytes(froms), StreamUtils.bytes(tos)); | |
67 | } | |
68 | ||
69 | /** | |
70 | * Create a {@link ReplaceInputStream} that will replace all <tt>froms</tt> | |
71 | * with <tt>tos</tt>. | |
72 | * <p> | |
73 | * Note that they will be replaced in order, and that for each <tt>from</tt> | |
74 | * a <tt>to</tt> must correspond. | |
75 | * | |
76 | * @param in | |
77 | * the under-laying {@link InputStream} | |
78 | * @param froms | |
79 | * the values to replace | |
80 | * @param tos | |
81 | * the values to replace with | |
82 | */ | |
83 | public ReplaceInputStream(InputStream in, byte[][] froms, byte[][] tos) { | |
6ef54b36 | 84 | super(in); |
627f866e NR |
85 | |
86 | if (froms.length != tos.length) { | |
87 | throw new IllegalArgumentException( | |
88 | "For replacing, each FROM must have a corresponding TO"); | |
89 | } | |
90 | ||
91 | this.froms = froms; | |
92 | this.tos = tos; | |
93 | ||
94 | for (int i = 0; i < tos.length; i++) { | |
95 | maxToSize = Math.max(maxToSize, tos[i].length); | |
96 | } | |
6ef54b36 NR |
97 | |
98 | source = new byte[4096]; | |
99 | spos = 0; | |
100 | slen = 0; | |
101 | } | |
102 | ||
103 | @Override | |
104 | protected int read(InputStream in, byte[] buffer) throws IOException { | |
627f866e | 105 | if (buffer.length < maxToSize || source.length < maxToSize * 2) { |
6ef54b36 | 106 | throw new IOException( |
627f866e | 107 | "An underlaying buffer is too small for these replace values"); |
6ef54b36 NR |
108 | } |
109 | ||
110 | if (spos >= slen) { | |
111 | spos = 0; | |
112 | slen = in.read(source); | |
113 | } | |
114 | ||
115 | // Note: very simple, not efficient implementation, sorry. | |
116 | int count = 0; | |
627f866e NR |
117 | while (spos < slen && count < buffer.length - maxToSize) { |
118 | boolean replaced = false; | |
119 | for (int i = 0; i < froms.length; i++) { | |
120 | if (froms[i] != null && froms[i].length > 0 | |
121 | && StreamUtils.startsWith(froms[i], source, spos, slen)) { | |
122 | if (tos[i] != null && tos[i].length > 0) { | |
123 | System.arraycopy(tos[i], 0, buffer, spos, tos[i].length); | |
124 | count += tos[i].length; | |
125 | } | |
126 | ||
127 | spos += froms[i].length; | |
128 | replaced = true; | |
129 | break; | |
130 | } | |
131 | } | |
132 | ||
133 | if (!replaced) { | |
876dbf8b | 134 | buffer[count++] = source[spos++]; |
6ef54b36 NR |
135 | } |
136 | } | |
137 | ||
138 | return count; | |
139 | } | |
6ef54b36 | 140 | } |