1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package org.archive.io;
24
25
26 import java.io.IOException;
27
28
29 /***
30 * Enables multiple concurrent streams based on the same underlying stream.
31 *
32 * @author pjack
33 */
34 public class SafeSeekInputStream extends SeekInputStream {
35
36
37 /***
38 * The underlying stream.
39 */
40 private SeekInputStream input;
41
42
43 /***
44 * The expected position of the underlying stream.
45 */
46 private long expected;
47
48
49 /***
50 * Constructor. The given stream will be positioned to 0 so that an
51 * accurate position can be tracked.
52 *
53 * @param input the underlying input stream
54 * @throws IOException if an IO error occurs
55 */
56 public SafeSeekInputStream(SeekInputStream input) throws IOException {
57 this.input = input;
58 this.expected = input.position();
59 }
60
61
62 /***
63 * Ensures that the underlying stream's position is what we expect to be.
64 *
65 * @throws IOException if an IO error occurs
66 */
67 private void ensure() throws IOException {
68 if (expected != input.position()) {
69 input.position(expected);
70 }
71 }
72
73
74 @Override
75 public int read() throws IOException {
76 ensure();
77 int c = input.read();
78 if (c >= 0) {
79 expected++;
80 }
81 return c;
82 }
83
84
85 @Override
86 public int read(byte[] buf, int ofs, int len) throws IOException {
87 ensure();
88 int r = input.read(buf, ofs, len);
89 if (r > 0) {
90 expected += r;
91 }
92 return r;
93 }
94
95
96 @Override
97 public int read(byte[] buf) throws IOException {
98 ensure();
99 int r = input.read(buf);
100 if (r > 0) {
101 expected += r;
102 }
103 return r;
104 }
105
106
107 @Override
108 public long skip(long c) throws IOException {
109 ensure();
110 long r = input.skip(c);
111 if (r > 0) {
112 expected += r;
113 }
114 return r;
115 }
116
117
118 public void position(long p) throws IOException {
119 input.position(p);
120 expected = p;
121 }
122
123
124 public long position() throws IOException {
125 return expected;
126 }
127
128 }