1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.util.io;
12
13 import java.io.IOException;
14 import java.io.InputStream;
15 import java.util.Iterator;
16 import java.util.LinkedList;
17
18
19
20
21
22
23
24
25
26
27
28
29 public class UnionInputStream extends InputStream {
30 private static final InputStream EOF = new InputStream() {
31 @Override
32 public int read() throws IOException {
33 return -1;
34 }
35 };
36
37 private final LinkedList<InputStream> streams = new LinkedList<>();
38
39
40
41
42 public UnionInputStream() {
43
44 }
45
46
47
48
49
50
51
52
53
54
55 public UnionInputStream(InputStream... inputStreams) {
56 for (InputStream i : inputStreams)
57 add(i);
58 }
59
60 private InputStream head() {
61 return streams.isEmpty() ? EOF : streams.getFirst();
62 }
63
64 private void pop() throws IOException {
65 if (!streams.isEmpty())
66 streams.removeFirst().close();
67 }
68
69
70
71
72
73
74
75
76
77 public void add(InputStream in) {
78 streams.add(in);
79 }
80
81
82
83
84
85
86
87
88
89
90 public boolean isEmpty() {
91 return streams.isEmpty();
92 }
93
94
95 @Override
96 public int read() throws IOException {
97 for (;;) {
98 final InputStream in = head();
99 final int r = in.read();
100 if (0 <= r)
101 return r;
102 else if (in == EOF)
103 return -1;
104 else
105 pop();
106 }
107 }
108
109
110 @Override
111 public int read(byte[] b, int off, int len) throws IOException {
112 if (len == 0)
113 return 0;
114 for (;;) {
115 final InputStream in = head();
116 final int n = in.read(b, off, len);
117 if (0 < n)
118 return n;
119 else if (in == EOF)
120 return -1;
121 else
122 pop();
123 }
124 }
125
126
127 @Override
128 public int available() throws IOException {
129 return head().available();
130 }
131
132
133 @Override
134 public long skip(long count) throws IOException {
135 long skipped = 0;
136 long cnt = count;
137 while (0 < cnt) {
138 final InputStream in = head();
139 final long n = in.skip(cnt);
140 if (0 < n) {
141 skipped += n;
142 cnt -= n;
143
144 } else if (in == EOF) {
145 return skipped;
146
147 } else {
148
149
150
151
152 final int r = in.read();
153 if (r < 0) {
154 pop();
155 if (0 < skipped)
156 break;
157 } else {
158 skipped += 1;
159 cnt -= 1;
160 }
161 }
162 }
163 return skipped;
164 }
165
166
167 @Override
168 public void close() throws IOException {
169 IOException err = null;
170
171 for (Iterator<InputStream> i = streams.iterator(); i.hasNext();) {
172 try {
173 i.next().close();
174 } catch (IOException closeError) {
175 err = closeError;
176 }
177 i.remove();
178 }
179
180 if (err != null)
181 throw err;
182 }
183 }