blob: fab854bef1eaf102f637bbd3da0b7c706196a847 [file] [log] [blame]
Constantin Kaplinsky903009e2002-05-20 10:55:47 +00001//
2// Copyright (C) 2002 HorizonLive.com, Inc. All Rights Reserved.
3//
4// This is free software; you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation; either version 2 of the License, or
7// (at your option) any later version.
8//
9// This software is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this software; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17// USA.
18//
19
20//
21// FbsInputStream.java
22//
23
24import java.io.*;
25
26class FbsInputStream extends InputStream {
27
28 protected InputStream in;
29 protected long startTime;
30 protected long timeOffset;
31
32 protected byte[] buffer;
33 protected int bufferSize;
34 protected int bufferPos;
35
36 //
37 // Constructors.
38 //
39
40 FbsInputStream() throws IOException {
41 throw new IOException("FbsInputStream: no such constructor");
42 }
43
44 FbsInputStream(InputStream in) throws IOException
45 {
46 this.in = in;
47 startTime = System.currentTimeMillis();
48 timeOffset = 0;
49
50 byte[] b = new byte[12];
51 readFully(b);
52
53 if (b[0] != 'F' || b[1] != 'B' || b[2] != 'S' || b[3] != ' ' ||
54 b[4] != '0' || b[5] != '0' || b[6] != '1' || b[7] != '.' ||
55 b[8] < '0' || b[8] > '9' || b[9] < '0' || b[9] > '9' ||
56 b[10] < '0' || b[10] > '9' || b[11] != '\n') {
57 throw new IOException("Incorrect protocol version");
58 }
59
60 buffer = null;
61 bufferSize = 0;
62 bufferPos = 0;
63 }
64
65 //
66 // Basic methods overriding InputStream's methods.
67 //
68
69 public int read() throws IOException
70 {
71 while (bufferSize == 0) {
72 if (!fillBuffer())
73 return -1;
74 }
75 bufferSize--;
76 return buffer[bufferPos++] & 0xFF;
77 }
78
79 public int available() throws IOException
80 {
81 // FIXME: This will work incorrectly if our caller will wait until
82 // some amount of data is available when the buffer contains less
83 // data than then that. Current implementation never reads more
84 // data until the buffer is fully exhausted.
85 return bufferSize;
86 }
87
88 public void close() throws IOException
89 {
90 in.close();
91 in = null;
92 startTime = 0;
93 timeOffset = 0;
94
95 buffer = null;
96 bufferSize = 0;
97 bufferPos = 0;
98 }
99
100 //
101 // Methods providing additional functionality.
102 //
103
104 public void resumeReading()
105 {
106 startTime = System.currentTimeMillis() - timeOffset;
107 }
108
109 //
110 // Methods for internal use.
111 //
112
113 private boolean fillBuffer() throws IOException
114 {
115 bufferSize = (int)readUnsigned32();
116 if (bufferSize >= 0) {
117 int realSize = (bufferSize + 3) & 0xFFFFFFFC;
118 buffer = new byte[realSize];
119 readFully(buffer);
120 bufferPos = 0;
121
122 timeOffset = readUnsigned32();
123 }
124
125 if (bufferSize < 0 || timeOffset < 0) {
126 buffer = null;
127 bufferSize = 0;
128 bufferPos = 0;
129 return false;
130 }
131
132 while (true) {
133 long timeDiff = startTime + timeOffset - System.currentTimeMillis();
134 if (timeDiff <= 0) {
135 break;
136 }
137 try {
138 Thread.currentThread().sleep(timeDiff);
139 } catch (InterruptedException e) {
140 }
141 }
142
143 return true;
144 }
145
146 private long readUnsigned32() throws IOException
147 {
148 byte[] buf = new byte[4];
149 if (!readFully(buf))
150 return -1;
151
152 return ((long)(buf[0] & 0xFF) << 24 |
153 (buf[1] & 0xFF) << 16 |
154 (buf[2] & 0xFF) << 8 |
155 (buf[3] & 0xFF));
156 }
157
158 private boolean readFully(byte[] b) throws IOException
159 {
160 int off = 0;
161 int len = b.length;
162
163 while (off != len) {
164 int count = in.read(b, off, len - off);
165 if (count < 0) {
166 return false;
167 }
168 off += count;
169 }
170
171 return true;
172 }
173}
174