Source code: com/traxel/io/CopyrightedInputStream.java
1 /* $Id: CopyrightedInputStream.java,v 1.1 2001/03/22 12:03:45 cvsbob Exp $ */
2
3 package com.traxel.io;
4
5 import java.io.InputStream;
6 import java.io.IOException;
7 import java.io.FilterInputStream;
8
9 /**
10 * @author Josh Flowers
11 * @author Tom Moore
12 * @author Robert Bushman
13 */
14
15 public class CopyrightedInputStream extends FilterInputStream {
16
17 protected static final int DEFAULT_BUFFER_SIZE = 1024;
18 protected boolean _bufferCopyrightedData = false;
19 protected byte[] _copyrightedDataBuffer;
20 protected int _copyrightedDataBytesAvailable = 0;
21 protected StreamMixer _mixer;
22
23 // -------------------------------------------------------
24 // CONSTRUCTORS
25 // -------------------------------------------------------
26
27 /** Wraps the argument in a CopyrightedInputStream. */
28 public CopyrightedInputStream( InputStream in ) {
29 super( in );
30 _mixer = new StreamMixerSimple();
31 }
32
33 /**
34 * This constructor allows you to enable buffering
35 * of the copyrighted data. This uses the default
36 * buffer size of 1024 bytes, which is discarded
37 * when the buffer fills, so be sure to take it
38 * if you want it.
39 */
40 public CopyrightedInputStream( InputStream in,
41 boolean bufferCopyrightedData ) {
42 super( in );
43 _bufferCopyrightedData = bufferCopyrightedData;
44 if( _bufferCopyrightedData ) {
45 _copyrightedDataBuffer = new byte[DEFAULT_BUFFER_SIZE];
46 }
47 _mixer = new StreamMixerSimple();
48 }
49
50 /**
51 * Works just like the 2 arg constructor, but allows you
52 * to specify a larger buffer.
53 */
54 public CopyrightedInputStream( InputStream in,
55 boolean bufferCopyrightedData,
56 int copyrightedDataBufferSize ) {
57 super( in );
58 _bufferCopyrightedData = bufferCopyrightedData;
59 if( _bufferCopyrightedData ) {
60 _copyrightedDataBuffer = new byte[copyrightedDataBufferSize];
61 }
62 _mixer = new StreamMixerSimple();
63 }
64
65 // -----------------------------------------------------
66 // INPUT STREAM OVERRIDES
67 // -----------------------------------------------------
68
69 /**
70 * Reads the next available byte from the input stream.
71 * Handles the copyright byte if the byte is a key byte.
72 */
73 public int read() throws IOException {
74 StreamMixerPair pair = _mixer.readFrom( in );
75 if( _bufferCopyrightedData ) {
76 addCopyrightedDataBytes( pair.byproductBytes );
77 }
78 return( pair.targetByte );
79 }
80
81 /**
82 * Calls read( buffer, 0, buffer.length );
83 */
84 public int read( byte[] buffer ) throws IOException {
85 return( read( buffer, 0, buffer.length ) );
86 }
87
88 /**
89 * Recursively calls read()
90 */
91 public int read( byte[] buffer, int off, int len ) throws IOException {
92 int i;
93 for( i = 0; i < off; i++ ) {
94 if( read() == -1 ) { return( -1 ); }
95 }
96 for( i = 0; i < len && i < buffer.length; i++ ) {
97 int nextRead = read();
98 if( nextRead == -1 ) { return( i ); }
99 buffer[ i ] = (byte)nextRead;
100 }
101 return( i );
102 }
103
104 /**
105 * Returns super.available() / 2, which is the minimum
106 * number of available bytes (the number of bytes
107 * that are available if every byte is a key byte)
108 */
109 public int available() throws IOException {
110 return( _mixer.availableFrom( in ) );
111 }
112
113 /**
114 * Mark is not supported. Returns false.
115 */
116 public boolean markSupported() { return( false ); }
117
118 // ---------------------------------------------------------
119 // PUBLIC API BEYOND INPUT STREAM IMPLEMENTATION
120 // ---------------------------------------------------------
121
122 /**
123 * Returns a byte array the size of the available bytes
124 * in the copyrighted cache. Returns an array of size
125 * zero if buffering is off or there is no data available.
126 */
127 public byte[] getCopyrightedDataBuffer() {
128 byte[] returnBuffer = new byte[_copyrightedDataBytesAvailable];
129 for( int i = 0; i < _copyrightedDataBytesAvailable; i++ ) {
130 returnBuffer[i] = _copyrightedDataBuffer[i];
131 }
132 flushCopyrightedDataBuffer();
133 return( returnBuffer );
134 }
135
136 // -------------------------------------------------------
137 // INTERNAL METHODS
138 // --------------------------------------------------------
139
140 /**
141 * This doesn't even vaguely respect the input byte[].
142 * Make sure your buffer is large enough, and you
143 * retrieve it frequently.
144 */
145 protected void addCopyrightedDataBytes( byte[] byproductBytes ) {
146 // BUG: This really needs to be cleaned up.
147 int i;
148 int newByteCount =
149 _copyrightedDataBytesAvailable + byproductBytes.length;
150 if( newByteCount > _copyrightedDataBuffer.length ) {
151 flushCopyrightedDataBuffer();
152 }
153 int insertionStart = _copyrightedDataBytesAvailable;
154 int insertionEnd =
155 _copyrightedDataBytesAvailable + byproductBytes.length;
156 if( _copyrightedDataBuffer.length < insertionEnd ) {
157 insertionEnd = _copyrightedDataBuffer.length;
158 }
159 for( i = insertionStart; i < insertionEnd; i++ ) {
160 int byproductIndex = i - _copyrightedDataBytesAvailable;
161 _copyrightedDataBuffer[ i ] = byproductBytes[ byproductIndex ];
162 }
163 _copyrightedDataBytesAvailable = i;
164 }
165
166 protected void flushCopyrightedDataBuffer() {
167 _copyrightedDataBytesAvailable = 0;
168 }
169 }