All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.core.internal.localstore.SafeChunkyInputStream Maven / Gradle / Ivy

Go to download

AspectJ tools most notably contains the AspectJ compiler (AJC). AJC applies aspects to Java classes during compilation, fully replacing Javac for plain Java classes and also compiling native AspectJ or annotation-based @AspectJ syntax. Furthermore, AJC can weave aspects into existing class files in a post-compile binary weaving step. This library is a superset of AspectJ weaver and hence also of AspectJ runtime.

There is a newer version: 1.9.22.1
Show newest version
/*******************************************************************************
 * Copyright (c) 2000, 2014 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.core.internal.localstore;

import java.io.*;

/**
 * @see SafeChunkyOutputStream
 */
public class SafeChunkyInputStream extends InputStream {
	protected static final int BUFFER_SIZE = 8192;
	protected byte[] buffer;
	protected int bufferLength = 0;
	protected byte[] chunk;
	protected int chunkLength = 0;
	protected boolean endOfFile = false;
	protected InputStream input;
	protected int nextByteInBuffer = 0;
	protected int nextByteInChunk = 0;

	public SafeChunkyInputStream(File target) throws IOException {
		this(target, BUFFER_SIZE);
	}

	public SafeChunkyInputStream(File target, int bufferSize) throws IOException {
		input = new FileInputStream(target);
		buffer = new byte[bufferSize];
	}

	protected void accumulate(byte[] data, int start, int end) {
		byte[] result = new byte[chunk.length + end - start];
		System.arraycopy(chunk, 0, result, 0, chunk.length);
		System.arraycopy(data, start, result, chunk.length, end - start);
		chunk = result;
		chunkLength = chunkLength + end - start;
	}

	@Override
	public int available() {
		return chunkLength - nextByteInChunk;
	}

	protected void buildChunk() throws IOException {
		//read buffer loads of data until an entire chunk is accumulated
		while (true) {
			if (nextByteInBuffer + ILocalStoreConstants.CHUNK_DELIMITER_SIZE > bufferLength)
				shiftAndFillBuffer();
			int end = find(ILocalStoreConstants.END_CHUNK, nextByteInBuffer, bufferLength, true);
			if (end != -1) {
				accumulate(buffer, nextByteInBuffer, end);
				nextByteInBuffer = end + ILocalStoreConstants.CHUNK_DELIMITER_SIZE;
				return;
			}
			accumulate(buffer, nextByteInBuffer, bufferLength);
			bufferLength = input.read(buffer);
			nextByteInBuffer = 0;
			if (bufferLength == -1) {
				endOfFile = true;
				return;
			}
		}
	}

	@Override
	public void close() throws IOException {
		input.close();
	}

	protected boolean compare(byte[] source, byte[] target, int startIndex) {
		for (byte element : target) {
			if (source[startIndex] != element)
				return false;
			startIndex++;
		}
		return true;
	}

	protected int find(byte[] pattern, int startIndex, int endIndex, boolean accumulate) throws IOException {
		int pos = findByte(pattern[0], startIndex, endIndex);
		if (pos == -1)
			return -1;
		if (pos + ILocalStoreConstants.CHUNK_DELIMITER_SIZE > bufferLength) {
			if (accumulate)
				accumulate(buffer, nextByteInBuffer, pos);
			nextByteInBuffer = pos;
			pos = 0;
			shiftAndFillBuffer();
		}
		if (compare(buffer, pattern, pos))
			return pos;
		return find(pattern, pos + 1, endIndex, accumulate);
	}

	protected int findByte(byte target, int startIndex, int endIndex) {
		while (startIndex < endIndex) {
			if (buffer[startIndex] == target)
				return startIndex;
			startIndex++;
		}
		return -1;
	}

	protected void findChunkStart() throws IOException {
		if (nextByteInBuffer + ILocalStoreConstants.CHUNK_DELIMITER_SIZE > bufferLength)
			shiftAndFillBuffer();
		int begin = find(ILocalStoreConstants.BEGIN_CHUNK, nextByteInBuffer, bufferLength, false);
		if (begin != -1) {
			nextByteInBuffer = begin + ILocalStoreConstants.CHUNK_DELIMITER_SIZE;
			return;
		}
		bufferLength = input.read(buffer);
		nextByteInBuffer = 0;
		if (bufferLength == -1) {
			resetChunk();
			endOfFile = true;
			return;
		}
		findChunkStart();
	}

	@Override
	public int read() throws IOException {
		if (endOfFile)
			return -1;
		// if there are bytes left in the chunk, return the first available
		if (nextByteInChunk < chunkLength)
			return chunk[nextByteInChunk++] & 0xFF;
		// Otherwise the chunk is empty so clear the current one, get the next
		// one and recursively call read.  Need to recur as the chunk may be
		// real but empty.
		resetChunk();
		findChunkStart();
		if (endOfFile)
			return -1;
		buildChunk();
		refineChunk();
		return read();
	}

	/**
	 * Skip over any begin chunks in the current chunk.  This could be optimized
	 * to skip at the same time as we are scanning the buffer.
	 */
	protected void refineChunk() {
		int start = chunkLength - ILocalStoreConstants.CHUNK_DELIMITER_SIZE;
		if (start < 0)
			return;
		for (int i = start; i >= 0; i--) {
			if (compare(chunk, ILocalStoreConstants.BEGIN_CHUNK, i)) {
				nextByteInChunk = i + ILocalStoreConstants.CHUNK_DELIMITER_SIZE;
				return;
			}
		}
	}

	protected void resetChunk() {
		chunk = new byte[0];
		chunkLength = 0;
		nextByteInChunk = 0;
	}

	protected void shiftAndFillBuffer() throws IOException {
		int length = bufferLength - nextByteInBuffer;
		System.arraycopy(buffer, nextByteInBuffer, buffer, 0, length);
		nextByteInBuffer = 0;
		bufferLength = length;
		int read = input.read(buffer, bufferLength, buffer.length - bufferLength);
		if (read != -1)
			bufferLength += read;
		else {
			resetChunk();
			endOfFile = true;
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy