• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 Google Inc. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 package com.google.archivepatcher.generator;
16 
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.io.OutputStream;
20 
21 /**
22  * A simple {@link OutputStream} that requires all bytes that are written to match bytes from a
23  * specified corresponding {@link InputStream}. Any length or content mismatch results in the stream
24  * being closed and an error being raised.
25  * <p>
26  * Every call to one of the write(...) methods results in reading the same total number of bytes
27  * from the {@link InputStream}. The bytes in both streams must match exactly.
28  */
29 public class MatchingOutputStream extends OutputStream {
30 
31   /**
32    * The bytes to match against.
33    */
34   private final InputStream expectedBytesStream;
35 
36   /**
37    * The buffer for reading bytes from the input stream for matching.
38    */
39   private final byte[] buffer;
40 
41   /**
42    * Constructs a new stream that will match against the the specified {@link InputStream}.
43    * @param expectedBytesStream stream of bytes to expect to see
44    * @param matchBufferSize the number of bytes to reserve for matching against the specified
45    * {@link InputStream}. This
46    */
MatchingOutputStream(InputStream expectedBytesStream, int matchBufferSize)47   public MatchingOutputStream(InputStream expectedBytesStream, int matchBufferSize) {
48     if (matchBufferSize < 1) {
49       throw new IllegalArgumentException("buffer size must be >= 1");
50     }
51     this.expectedBytesStream = expectedBytesStream;
52     this.buffer = new byte[matchBufferSize];
53   }
54 
55   @Override
write(int b)56   public void write(int b) throws IOException {
57     int expected = expectedBytesStream.read();
58     if (expected == -1) {
59       throw new MismatchException("EOF reached in expectedBytesStream");
60     }
61     if (expected != b) {
62       throw new MismatchException("Data does not match");
63     }
64   }
65 
66   @Override
write(byte[] b)67   public void write(byte[] b) throws IOException {
68     write(b, 0, b.length);
69   }
70 
71   @Override
write(byte[] dataToWrite, int offset, int length)72   public void write(byte[] dataToWrite, int offset, int length) throws IOException {
73     int numReadSoFar = 0;
74     while (numReadSoFar < length) {
75       int maxToRead = Math.min(buffer.length, length - numReadSoFar);
76       int numReadThisLoop = expectedBytesStream.read(buffer, 0, maxToRead);
77       if (numReadThisLoop == -1) {
78         throw new MismatchException("EOF reached in expectedBytesStream");
79       }
80       for (int matchCount = 0; matchCount < numReadThisLoop; matchCount++) {
81         if (buffer[matchCount] != dataToWrite[offset + numReadSoFar + matchCount]) {
82           throw new MismatchException("Data does not match");
83         }
84       }
85       numReadSoFar += numReadThisLoop;
86     }
87   }
88 
89   @Override
close()90   public void close() throws IOException {
91     expectedBytesStream.close();
92   }
93 
94   /**
95    * Expects the end-of-file to be reached in the associated {@link InputStream}.
96    * @throws IOException if the end-of-file has not yet been reached in the associated
97    * {@link InputStream}
98    */
expectEof()99   public void expectEof() throws IOException {
100     if (expectedBytesStream.read() != -1) {
101       throw new MismatchException("EOF not reached in expectedBytesStream");
102     }
103   }
104 }
105