1 /***
2 * Ambient - A music player for the Android platform
3 Copyright (C) 2007 Martin Vysny
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 package sk.baka.ambient.commons;
20
21 import java.io.IOException;
22 import java.io.InputStream;
23
24 /***
25 * Counts bytes which are being read.
26 *
27 * @author Martin Vysny
28 */
29 public abstract class CountingInputStream extends InputStream {
30 @Override
31 public int read() throws IOException {
32 final int result = in.read();
33 if (result >= 0) {
34 currentPosition++;
35 checkPos();
36 }
37 return result;
38 }
39
40 private void checkPos() {
41 if (currentPosition >= nextEventPosition) {
42 nextEventPosition += blockLength;
43 countEvent(currentPosition);
44 }
45 }
46
47 @Override
48 public int read(byte[] buffer, int offset, int count) throws IOException {
49 final int result = in.read(buffer, offset, count);
50 if (result > 0) {
51 currentPosition += result;
52 checkPos();
53 }
54 return result;
55 }
56
57 @Override
58 public int read(byte[] buffer) throws IOException {
59 final int result = in.read(buffer);
60 if (result > 0) {
61 currentPosition += result;
62 checkPos();
63 }
64 return result;
65 }
66
67 @Override
68 public long skip(long count) throws IOException {
69 final long result = in.skip(count);
70 currentPosition += result;
71 checkPos();
72 return result;
73 }
74
75 @Override
76 public synchronized void mark(int readlimit) {
77 in.mark(readlimit);
78 markedPosition = currentPosition;
79 }
80
81 private long markedPosition = 0;
82
83 @Override
84 public synchronized void reset() throws IOException {
85 in.reset();
86 if (!markSupported()) {
87 currentPosition = 0;
88 } else {
89 currentPosition = markedPosition;
90 }
91 }
92
93 /***
94 * Fire events only when a block of given size (in bytes) has been read.
95 * This prevents firing events after each byte read.
96 */
97 public final int blockLength;
98 private final InputStream in;
99
100 /***
101 * Creates new counting stream instance.
102 *
103 * @param in
104 * poll this stream.
105 * @param blockLength
106 * Fire events only when a block of given size (in bytes) has
107 * been read. This prevents firing events after each byte read.
108 */
109 public CountingInputStream(final InputStream in, final int blockLength) {
110 super();
111 this.in = in;
112 this.blockLength = blockLength;
113 nextEventPosition = blockLength;
114 }
115
116 private long currentPosition = 0;
117
118 /***
119 * Returns number of bytes already read.
120 *
121 * @return the number of bytes.
122 */
123 public long getCurrentPosition() {
124 return currentPosition;
125 }
126
127 private long nextEventPosition;
128
129 /***
130 * Invoked when the position
131 *
132 * @param currentPosition
133 */
134 protected abstract void countEvent(final long currentPosition);
135
136 @Override
137 public int available() throws IOException {
138 return in.available();
139 }
140
141 @Override
142 public void close() throws IOException {
143 in.close();
144 }
145
146 @Override
147 public boolean markSupported() {
148 return in.markSupported();
149 }
150 }