1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 package com.aragost.javahg.internals;
27
28 import java.io.BufferedInputStream;
29 import java.io.ByteArrayOutputStream;
30 import java.io.IOException;
31 import java.io.InputStream;
32 import java.nio.charset.CharsetDecoder;
33
34 import com.aragost.javahg.DateTime;
35
36
37
38
39
40 public class HgInputStream extends BufferedInputStream {
41
42 private CharsetDecoder textDecoder;
43
44
45
46
47
48
49
50
51 public HgInputStream(InputStream in, CharsetDecoder textDecoder) {
52 super(in);
53 this.textDecoder = textDecoder;
54 }
55
56
57
58
59
60
61
62
63 public int peek() throws IOException {
64 mark(1);
65 int result = read();
66 reset();
67 return result;
68 }
69
70
71
72
73
74 public boolean isEof() throws IOException {
75 return peek() == -1;
76 }
77
78
79
80
81
82
83
84
85
86
87 public byte[] next(int length) throws IOException {
88 byte[] bytes = new byte[length];
89 int remaining = length;
90 while (remaining > 0) {
91 int n = read(bytes, length - remaining, remaining);
92 if (n == -1) {
93 return null;
94 }
95 remaining = remaining - n;
96 }
97 return bytes;
98 }
99
100
101
102
103
104
105
106
107
108 public String nextAsText(int length) throws IOException {
109 byte[] bytes = next(length);
110 if (bytes == null) {
111 return null;
112 } else {
113 return Utils.decodeBytes(bytes, this.textDecoder);
114 }
115 }
116
117
118
119
120
121
122
123
124
125
126
127 public boolean match(byte[] bytes) throws IOException {
128 mark(bytes.length);
129 for (int i = 0; i < bytes.length; i++) {
130 int n = read();
131 if (n == -1 || (byte) n != bytes[i]) {
132 reset();
133 return false;
134 }
135 }
136 return true;
137 }
138
139
140
141
142
143
144
145
146
147
148
149 public boolean match(int b) throws IOException {
150 mark(1);
151 int n = read();
152 if (n == b) {
153 return true;
154 } else {
155 reset();
156 return false;
157 }
158 }
159
160
161
162
163
164
165
166
167
168
169 public void mustMatch(byte[] bytes) throws IOException, UnexpectedCommandOutputException {
170 for (int i = 0; i < bytes.length; i++) {
171 mustMatch(bytes[i]);
172 }
173 }
174
175
176
177
178
179
180
181
182
183
184
185 public void mustMatch(int b) throws IOException, UnexpectedCommandOutputException {
186 int n = read();
187 if ((byte) n != b) {
188 throw new UnexpectedCommandOutputException("Got " + n + ", but expected " + b);
189 }
190 }
191
192
193
194
195
196
197
198
199
200
201
202 public byte[] upTo(byte[] stop) throws IOException {
203 if (stop.length == 0) {
204 return new byte[0];
205 }
206 ByteArrayOutputStream byteStream = new ByteArrayOutputStream(80);
207 int stopIndex = 0;
208
209 while (true) {
210 int b = read();
211 if (b == -1) {
212 return null;
213
214
215 }
216 if (stop[stopIndex] == (byte) b) {
217 if (stopIndex == 0) {
218 mark(stop.length);
219 }
220 stopIndex++;
221 if (stopIndex == stop.length) {
222 break;
223 }
224 } else {
225 if (stopIndex > 0) {
226 byteStream.write(stop, 0, 1);
227 reset();
228 stopIndex = 0;
229 } else {
230 byteStream.write(b);
231 }
232 }
233 }
234 return byteStream.toByteArray();
235 }
236
237
238
239
240
241
242
243
244
245
246
247 public byte[] upTo(int stop) throws IOException {
248 ByteArrayOutputStream byteStream = new ByteArrayOutputStream(40);
249 while (true) {
250 int n = read();
251 if (n == -1) {
252 return null;
253 }
254 if (n == stop) {
255 break;
256 }
257 byteStream.write(n);
258 }
259 return byteStream.toByteArray();
260 }
261
262
263
264
265
266
267
268
269
270
271 public boolean find(byte[] bytes) throws IOException {
272 int index = 0;
273 int length = bytes.length;
274 if (length == 0) {
275 throw new IllegalArgumentException("Can't search for nothing");
276 }
277 while (true) {
278 int b = read();
279 if (b == -1) {
280 return false;
281 }
282 if (bytes[index] == (byte) b) {
283 if (index == 0) {
284 mark(length);
285 }
286 index++;
287 if (index == length) {
288 return true;
289 }
290 } else if (index > 0) {
291 reset();
292 index = 0;
293 }
294 }
295 }
296
297
298
299
300
301
302
303
304 public boolean find(int b) throws IOException {
305 while (true) {
306 int n = read();
307 if (n == -1) {
308 return false;
309 }
310 if (n == b) {
311 return true;
312 }
313 }
314
315 }
316
317
318
319
320
321
322
323
324
325
326 public int decimalIntUpTo(int stop) throws IOException {
327 int result = 0;
328 while (true) {
329 int n = read();
330 if (n == -1 || n == stop) {
331 return result;
332 }
333 int digit = n - '0';
334 if (digit < 0 || digit >= 10) {
335 throw new IOException("A non-digit found: " + (char) n);
336 }
337 result = result * 10 + digit;
338 }
339 }
340
341
342
343
344
345
346
347
348
349
350
351 public Integer readDecimal() throws IOException {
352 boolean somethingRead = false;
353 int result = 0;
354 while (true) {
355 mark(1);
356 int n = read();
357 if (n == -1) {
358 break;
359 }
360 int digit = n - '0';
361 if (digit >= 0 && digit < 10) {
362 somethingRead = true;
363 result = 10 * result + digit;
364 } else {
365 reset();
366 break;
367 }
368 }
369 return somethingRead ? Integer.valueOf(result) : null;
370 }
371
372
373
374
375
376
377
378
379
380
381
382
383
384 public int revisionUpTo(int stop) throws IOException {
385 while (peek() == ' ') {
386 read();
387 }
388 if (peek() == '-') {
389 read();
390 mustMatch('1');
391 mustMatch(stop);
392 return -1;
393 } else {
394 return decimalIntUpTo(stop);
395 }
396 }
397
398
399
400
401
402
403
404
405
406
407
408
409
410 public DateTime dateTimeUpTo(int stopByte) throws IOException {
411 long millis = 1000L * decimalIntUpTo(' ');
412 boolean negative = match('-');
413 int timezoneOffset = 1000 * decimalIntUpTo(stopByte);
414 if (negative) {
415 timezoneOffset = -timezoneOffset;
416 }
417 return new DateTime(millis, timezoneOffset);
418 }
419
420
421
422
423
424
425
426
427
428
429
430 public String textUpTo(byte[] end) throws IOException {
431 byte[] bytes = upTo(end);
432 if (bytes == null) {
433 return null;
434 } else {
435 return Utils.decodeBytes(bytes, this.textDecoder);
436 }
437 }
438
439
440
441
442
443
444
445
446
447
448
449 public String textUpTo(int b) throws IOException {
450 byte[] bytes = upTo(b);
451 if (bytes == null) {
452 return null;
453 } else {
454 return Utils.decodeBytes(bytes, this.textDecoder);
455 }
456
457 }
458
459
460
461
462
463
464 public void consumeAll() throws IOException {
465 Utils.consumeAll(this);
466 }
467
468 @Override
469 public String toString() {
470
471 StringBuilder buffer = new StringBuilder();
472
473 buffer.append(new String(buf, 0, this.pos));
474 buffer.append(">@<");
475 buffer.append(new String(buf, this.pos, this.count));
476
477 return buffer.toString();
478 }
479 }