code cleanup, fix for ReplaceInputStream
[nikiroo-utils.git] / src / be / nikiroo / utils / streams / ReplaceOutputStream.java
1 package be.nikiroo.utils.streams;
2
3 import java.io.IOException;
4 import java.io.OutputStream;
5
6 /**
7 * This {@link OutputStream} will change some of its content by replacing it
8 * with something else.
9 *
10 * @author niki
11 */
12 public class ReplaceOutputStream extends BufferedOutputStream {
13 private byte[][] froms;
14 private byte[][] tos;
15
16 /**
17 * Create a {@link ReplaceOutputStream} that will replace <tt>from</tt> with
18 * <tt>to</tt>.
19 *
20 * @param out
21 * the under-laying {@link OutputStream}
22 * @param from
23 * the {@link String} to replace
24 * @param to
25 * the {@link String} to replace with
26 */
27 public ReplaceOutputStream(OutputStream out, String from, String to) {
28 this(out, StreamUtils.bytes(from), StreamUtils.bytes(to));
29 }
30
31 /**
32 * Create a {@link ReplaceOutputStream} that will replace <tt>from</tt> with
33 * <tt>to</tt>.
34 *
35 * @param out
36 * the under-laying {@link OutputStream}
37 * @param from
38 * the value to replace
39 * @param to
40 * the value to replace with
41 */
42 public ReplaceOutputStream(OutputStream out, byte[] from, byte[] to) {
43 this(out, new byte[][] { from }, new byte[][] { to });
44 }
45
46 /**
47 * Create a {@link ReplaceOutputStream} that will replace all <tt>froms</tt>
48 * with <tt>tos</tt>.
49 * <p>
50 * Note that they will be replaced in order, and that for each <tt>from</tt>
51 * a <tt>to</tt> must correspond.
52 *
53 * @param out
54 * the under-laying {@link OutputStream}
55 * @param froms
56 * the values to replace
57 * @param tos
58 * the values to replace with
59 */
60 public ReplaceOutputStream(OutputStream out, String[] froms, String[] tos) {
61 this(out, StreamUtils.bytes(froms), StreamUtils.bytes(tos));
62 }
63
64 /**
65 * Create a {@link ReplaceOutputStream} that will replace all <tt>froms</tt>
66 * with <tt>tos</tt>.
67 * <p>
68 * Note that they will be replaced in order, and that for each <tt>from</tt>
69 * a <tt>to</tt> must correspond.
70 *
71 * @param out
72 * the under-laying {@link OutputStream}
73 * @param froms
74 * the values to replace
75 * @param tos
76 * the values to replace with
77 */
78 public ReplaceOutputStream(OutputStream out, byte[][] froms, byte[][] tos) {
79 super(out);
80 bypassFlush = false;
81
82 if (froms.length != tos.length) {
83 throw new IllegalArgumentException(
84 "For replacing, each FROM must have a corresponding TO");
85 }
86
87 this.froms = froms;
88 this.tos = tos;
89 }
90
91 /**
92 * Flush the {@link BufferedOutputStream}, write the current buffered data
93 * to (and optionally also flush) the under-laying stream.
94 * <p>
95 * If {@link BufferedOutputStream#bypassFlush} is false, all writes to the
96 * under-laying stream are done in this method.
97 * <p>
98 * This can be used if you want to write some data in the under-laying
99 * stream yourself (in that case, flush this {@link BufferedOutputStream}
100 * with or without flushing the under-laying stream, then you can write to
101 * the under-laying stream).
102 * <p>
103 * <b>But be careful!</b> If a replacement could be done with the end o the
104 * currently buffered data and the start of the data to come, we obviously
105 * will not be able to do it.
106 *
107 * @param includingSubStream
108 * also flush the under-laying stream
109 * @throws IOException
110 * in case of I/O error
111 */
112 @Override
113 public void flush(boolean includingSubStream) throws IOException {
114 // Note: very simple, not efficient implementation; sorry.
115 while (start < stop) {
116 boolean replaced = false;
117 for (int i = 0; i < froms.length; i++) {
118 if (froms[i] != null
119 && froms[i].length > 0
120 && StreamUtils
121 .startsWith(froms[i], buffer, start, stop)) {
122 if (tos[i] != null && tos[i].length > 0) {
123 out.write(tos[i]);
124 bytesWritten += tos[i].length;
125 }
126
127 start += froms[i].length;
128 replaced = true;
129 break;
130 }
131 }
132
133 if (!replaced) {
134 out.write(buffer[start++]);
135 bytesWritten++;
136 }
137 }
138
139 start = 0;
140 stop = 0;
141
142 if (includingSubStream) {
143 out.flush();
144 }
145 }
146 }