KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > internal > localstore > SafeChunkyInputStream


1 /*******************************************************************************
2  * Copyright (c) 2000, 2005 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.core.internal.localstore;
12
13 import java.io.*;
14
15 /**
16  * @see SafeChunkyOutputStream
17  */

18
19 public class SafeChunkyInputStream extends InputStream {
20     protected static final int BUFFER_SIZE = 8192;
21     protected byte[] buffer;
22     protected int bufferLength = 0;
23     protected byte[] chunk;
24     protected int chunkLength = 0;
25     protected boolean endOfFile = false;
26     protected InputStream input;
27     protected int nextByteInBuffer = 0;
28     protected int nextByteInChunk = 0;
29
30     public SafeChunkyInputStream(File target) throws IOException {
31         this(target, BUFFER_SIZE);
32     }
33
34     public SafeChunkyInputStream(File target, int bufferSize) throws IOException {
35         input = new FileInputStream(target);
36         buffer = new byte[bufferSize];
37     }
38
39     protected void accumulate(byte[] data, int start, int end) {
40         byte[] result = new byte[chunk.length + end - start];
41         System.arraycopy(chunk, 0, result, 0, chunk.length);
42         System.arraycopy(data, start, result, chunk.length, end - start);
43         chunk = result;
44         chunkLength = chunkLength + end - start;
45     }
46
47     public int available() throws IOException {
48         return chunkLength - nextByteInChunk;
49     }
50
51     protected void buildChunk() throws IOException {
52         //read buffer loads of data until an entire chunk is accumulated
53
while (true) {
54             if (nextByteInBuffer + ILocalStoreConstants.CHUNK_DELIMITER_SIZE > bufferLength)
55                 shiftAndFillBuffer();
56             int end = find(ILocalStoreConstants.END_CHUNK, nextByteInBuffer, bufferLength, true);
57             if (end != -1) {
58                 accumulate(buffer, nextByteInBuffer, end);
59                 nextByteInBuffer = end + ILocalStoreConstants.CHUNK_DELIMITER_SIZE;
60                 return;
61             }
62             accumulate(buffer, nextByteInBuffer, bufferLength);
63             bufferLength = input.read(buffer);
64             nextByteInBuffer = 0;
65             if (bufferLength == -1) {
66                 endOfFile = true;
67                 return;
68             }
69         }
70     }
71
72     public void close() throws IOException {
73         input.close();
74     }
75
76     protected boolean compare(byte[] source, byte[] target, int startIndex) {
77         for (int i = 0; i < target.length; i++) {
78             if (source[startIndex] != target[i])
79                 return false;
80             startIndex++;
81         }
82         return true;
83     }
84
85     protected int find(byte[] pattern, int startIndex, int endIndex, boolean accumulate) throws IOException {
86         int pos = findByte(pattern[0], startIndex, endIndex);
87         if (pos == -1)
88             return -1;
89         if (pos + ILocalStoreConstants.CHUNK_DELIMITER_SIZE > bufferLength) {
90             if (accumulate)
91                 accumulate(buffer, nextByteInBuffer, pos);
92             nextByteInBuffer = pos;
93             pos = 0;
94             shiftAndFillBuffer();
95         }
96         if (compare(buffer, pattern, pos))
97             return pos;
98         return find(pattern, pos + 1, endIndex, accumulate);
99     }
100
101     protected int findByte(byte target, int startIndex, int endIndex) {
102         while (startIndex < endIndex) {
103             if (buffer[startIndex] == target)
104                 return startIndex;
105             startIndex++;
106         }
107         return -1;
108     }
109
110     protected void findChunkStart() throws IOException {
111         if (nextByteInBuffer + ILocalStoreConstants.CHUNK_DELIMITER_SIZE > bufferLength)
112             shiftAndFillBuffer();
113         int begin = find(ILocalStoreConstants.BEGIN_CHUNK, nextByteInBuffer, bufferLength, false);
114         if (begin != -1) {
115             nextByteInBuffer = begin + ILocalStoreConstants.CHUNK_DELIMITER_SIZE;
116             return;
117         }
118         bufferLength = input.read(buffer);
119         nextByteInBuffer = 0;
120         if (bufferLength == -1) {
121             resetChunk();
122             endOfFile = true;
123             return;
124         }
125         findChunkStart();
126     }
127
128     public int read() throws IOException {
129         if (endOfFile)
130             return -1;
131         // if there are bytes left in the chunk, return the first available
132
if (nextByteInChunk < chunkLength)
133             return chunk[nextByteInChunk++] & 0xFF;
134         // Otherwise the chunk is empty so clear the current one, get the next
135
// one and recursively call read. Need to recur as the chunk may be
136
// real but empty.
137
resetChunk();
138         findChunkStart();
139         if (endOfFile)
140             return -1;
141         buildChunk();
142         refineChunk();
143         return read();
144     }
145
146     /**
147      * Skip over any begin chunks in the current chunk. This could be optimized
148      * to skip at the same time as we are scanning the buffer.
149      */

150     protected void refineChunk() {
151         int start = chunkLength - ILocalStoreConstants.CHUNK_DELIMITER_SIZE;
152         if (start < 0)
153             return;
154         for (int i = start; i >= 0; i--) {
155             if (compare(chunk, ILocalStoreConstants.BEGIN_CHUNK, i)) {
156                 nextByteInChunk = i + ILocalStoreConstants.CHUNK_DELIMITER_SIZE;
157                 return;
158             }
159         }
160     }
161
162     protected void resetChunk() {
163         chunk = new byte[0];
164         chunkLength = 0;
165         nextByteInChunk = 0;
166     }
167
168     protected void shiftAndFillBuffer() throws IOException {
169         int length = bufferLength - nextByteInBuffer;
170         System.arraycopy(buffer, nextByteInBuffer, buffer, 0, length);
171         nextByteInBuffer = 0;
172         bufferLength = length;
173         int read = input.read(buffer, bufferLength, buffer.length - bufferLength);
174         if (read != -1)
175             bufferLength += read;
176         else {
177             resetChunk();
178             endOfFile = true;
179         }
180     }
181 }
182
Popular Tags